1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.pm.pkg.mutate; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.ComponentName; 22 import android.content.pm.ApplicationInfo; 23 import android.content.pm.PackageManager; 24 import android.content.pm.overlay.OverlayPaths; 25 import android.util.ArraySet; 26 27 import com.android.server.pm.PackageSetting; 28 import com.android.server.pm.pkg.PackageUserStateImpl; 29 import com.android.server.pm.pkg.SuspendParams; 30 31 import java.util.concurrent.atomic.AtomicLong; 32 import java.util.function.Function; 33 34 public class PackageStateMutator { 35 36 private static final AtomicLong sStateChangeSequence = new AtomicLong(); 37 38 private final StateWriteWrapper mStateWrite = new StateWriteWrapper(); 39 40 private final Function<String, PackageSetting> mActiveStateFunction; 41 private final Function<String, PackageSetting> mDisabledStateFunction; 42 43 private final ArraySet<PackageSetting> mChangedStates = new ArraySet<>(); 44 PackageStateMutator(@onNull Function<String, PackageSetting> activeStateFunction, @NonNull Function<String, PackageSetting> disabledStateFunction)45 public PackageStateMutator(@NonNull Function<String, PackageSetting> activeStateFunction, 46 @NonNull Function<String, PackageSetting> disabledStateFunction) { 47 mActiveStateFunction = activeStateFunction; 48 mDisabledStateFunction = disabledStateFunction; 49 } 50 onPackageStateChanged()51 public static void onPackageStateChanged() { 52 sStateChangeSequence.incrementAndGet(); 53 } 54 55 @NonNull forPackage(@onNull String packageName)56 public PackageStateWrite forPackage(@NonNull String packageName) { 57 return setState(mActiveStateFunction.apply(packageName)); 58 } 59 60 @Nullable forPackageNullable(@onNull String packageName)61 public PackageStateWrite forPackageNullable(@NonNull String packageName) { 62 final PackageSetting packageState = mActiveStateFunction.apply(packageName); 63 setState(packageState); 64 if (packageState == null) { 65 return null; 66 } 67 68 return setState(packageState); 69 } 70 71 @NonNull forDisabledSystemPackage(@onNull String packageName)72 public PackageStateWrite forDisabledSystemPackage(@NonNull String packageName) { 73 return setState(mDisabledStateFunction.apply(packageName)); 74 } 75 76 @Nullable forDisabledSystemPackageNullable(@onNull String packageName)77 public PackageStateWrite forDisabledSystemPackageNullable(@NonNull String packageName) { 78 final PackageSetting packageState = mDisabledStateFunction.apply(packageName); 79 if (packageState == null) { 80 return null; 81 } 82 83 return setState(packageState); 84 } 85 86 @NonNull initialState(int changedPackagesSequenceNumber)87 public InitialState initialState(int changedPackagesSequenceNumber) { 88 return new InitialState(changedPackagesSequenceNumber, sStateChangeSequence.get()); 89 } 90 91 /** 92 * @return null if initial state is null or if nothing has changed, otherwise return result 93 * with what changed 94 */ 95 @Nullable generateResult(@ullable InitialState state, int changedPackagesSequenceNumber)96 public Result generateResult(@Nullable InitialState state, int changedPackagesSequenceNumber) { 97 if (state == null) { 98 return Result.SUCCESS; 99 } 100 101 boolean packagesChanged = changedPackagesSequenceNumber != state.mPackageSequence; 102 boolean stateChanged = sStateChangeSequence.get() != state.mStateSequence; 103 if (packagesChanged && stateChanged) { 104 return Result.PACKAGES_AND_STATE_CHANGED; 105 } else if (packagesChanged) { 106 return Result.PACKAGES_CHANGED; 107 } else if (stateChanged) { 108 return Result.STATE_CHANGED; 109 } else { 110 return Result.SUCCESS; 111 } 112 } 113 onFinished()114 public void onFinished() { 115 for (int index = 0; index < mChangedStates.size(); index++) { 116 mChangedStates.valueAt(index).onChanged(); 117 } 118 } 119 120 @NonNull setState(@ullable PackageSetting state)121 private StateWriteWrapper setState(@Nullable PackageSetting state) { 122 // State can be nullable because this infrastructure no-ops on non-existent states 123 if (state != null) { 124 mChangedStates.add(state); 125 } 126 return mStateWrite.setState(state); 127 } 128 129 public static class InitialState { 130 131 private final int mPackageSequence; 132 private final long mStateSequence; 133 InitialState(int packageSequence, long stateSequence)134 public InitialState(int packageSequence, long stateSequence) { 135 mPackageSequence = packageSequence; 136 mStateSequence = stateSequence; 137 } 138 } 139 140 public static class Result { 141 142 public static final Result SUCCESS = new Result(true, false, false, false); 143 public static final Result PACKAGES_CHANGED = new Result(false, true, false, false); 144 public static final Result STATE_CHANGED = new Result(false, false, true, false); 145 public static final Result PACKAGES_AND_STATE_CHANGED = new Result(false, true, true, false); 146 public static final Result SPECIFIC_PACKAGE_NULL = new Result(false, false, true, true); 147 148 private final boolean mCommitted; 149 private final boolean mPackagesChanged; 150 private final boolean mStateChanged; 151 private final boolean mSpecificPackageNull; 152 Result(boolean committed, boolean packagesChanged, boolean stateChanged, boolean specificPackageNull)153 public Result(boolean committed, boolean packagesChanged, boolean stateChanged, 154 boolean specificPackageNull) { 155 mCommitted = committed; 156 mPackagesChanged = packagesChanged; 157 mStateChanged = stateChanged; 158 mSpecificPackageNull = specificPackageNull; 159 } 160 isCommitted()161 public boolean isCommitted() { 162 return mCommitted; 163 } 164 isPackagesChanged()165 public boolean isPackagesChanged() { 166 return mPackagesChanged; 167 } 168 isStateChanged()169 public boolean isStateChanged() { 170 return mStateChanged; 171 } 172 isSpecificPackageNull()173 public boolean isSpecificPackageNull() { 174 return mSpecificPackageNull; 175 } 176 } 177 178 private static class StateWriteWrapper implements PackageStateWrite { 179 180 private final UserStateWriteWrapper mUserStateWrite = new UserStateWriteWrapper(); 181 182 @NonNull 183 private PackageSetting mState; 184 setState(PackageSetting state)185 public StateWriteWrapper setState(PackageSetting state) { 186 this.mState = state; 187 return this; 188 } 189 190 @NonNull 191 @Override userState(int userId)192 public PackageUserStateWrite userState(int userId) { 193 var userState = mState == null ? null : mState.getOrCreateUserState(userId); 194 if (userState != null) { 195 userState.setWatchable(mState); 196 } 197 return mUserStateWrite.setStates(userState); 198 } 199 200 @Override onChanged()201 public void onChanged() { 202 if (mState != null) { 203 mState.onChanged(); 204 } 205 } 206 207 @Override setLastPackageUsageTime(int reason, long timeInMillis)208 public PackageStateWrite setLastPackageUsageTime(int reason, long timeInMillis) { 209 if (mState != null) { 210 mState.getTransientState().setLastPackageUsageTimeInMills(reason, timeInMillis); 211 } 212 return this; 213 } 214 215 @Override setHiddenUntilInstalled(boolean value)216 public PackageStateWrite setHiddenUntilInstalled(boolean value) { 217 if (mState != null) { 218 mState.getTransientState().setHiddenUntilInstalled(value); 219 } 220 return this; 221 } 222 223 @NonNull 224 @Override setRequiredForSystemUser(boolean requiredForSystemUser)225 public PackageStateWrite setRequiredForSystemUser(boolean requiredForSystemUser) { 226 if (mState != null) { 227 if (requiredForSystemUser) { 228 mState.setPrivateFlags(mState.getPrivateFlags() 229 | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER); 230 } else { 231 mState.setPrivateFlags(mState.getPrivateFlags() 232 & ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER); 233 } 234 } 235 return this; 236 } 237 238 @NonNull 239 @Override setMimeGroup(@onNull String mimeGroup, @NonNull ArraySet<String> mimeTypes)240 public PackageStateWrite setMimeGroup(@NonNull String mimeGroup, 241 @NonNull ArraySet<String> mimeTypes) { 242 if (mState != null) { 243 mState.setMimeGroup(mimeGroup, mimeTypes); 244 } 245 return this; 246 } 247 248 @NonNull 249 @Override setCategoryOverride(@pplicationInfo.Category int category)250 public PackageStateWrite setCategoryOverride(@ApplicationInfo.Category int category) { 251 if (mState != null) { 252 mState.setCategoryOverride(category); 253 } 254 return this; 255 } 256 257 @NonNull 258 @Override setUpdateAvailable(boolean updateAvailable)259 public PackageStateWrite setUpdateAvailable(boolean updateAvailable) { 260 if (mState != null) { 261 mState.setUpdateAvailable(updateAvailable); 262 } 263 return this; 264 } 265 266 @NonNull 267 @Override setLoadingProgress(float progress)268 public PackageStateWrite setLoadingProgress(float progress) { 269 if (mState != null) { 270 mState.setLoadingProgress(progress); 271 } 272 return this; 273 } 274 275 @NonNull 276 @Override setLoadingCompletedTime(long loadingCompletedTime)277 public PackageStateWrite setLoadingCompletedTime(long loadingCompletedTime) { 278 if (mState != null) { 279 mState.setLoadingCompletedTime(loadingCompletedTime); 280 } 281 return this; 282 } 283 284 @NonNull 285 @Override setOverrideSeInfo(@ullable String newSeInfo)286 public PackageStateWrite setOverrideSeInfo(@Nullable String newSeInfo) { 287 if (mState != null) { 288 mState.getTransientState().setOverrideSeInfo(newSeInfo); 289 } 290 return this; 291 } 292 293 @NonNull 294 @Override setInstaller(@ullable String installerPackageName, int installerPackageUid)295 public PackageStateWrite setInstaller(@Nullable String installerPackageName, 296 int installerPackageUid) { 297 if (mState != null) { 298 mState.setInstallerPackage(installerPackageName, installerPackageUid); 299 } 300 return this; 301 } 302 303 @NonNull 304 @Override setUpdateOwner(@onNull String updateOwnerPackageName)305 public PackageStateWrite setUpdateOwner(@NonNull String updateOwnerPackageName) { 306 if (mState != null) { 307 mState.setUpdateOwnerPackage(updateOwnerPackageName); 308 } 309 return this; 310 } 311 312 private static class UserStateWriteWrapper implements PackageUserStateWrite { 313 314 @Nullable 315 private PackageUserStateImpl mUserState; 316 setStates(@ullable PackageUserStateImpl userState)317 public UserStateWriteWrapper setStates(@Nullable PackageUserStateImpl userState) { 318 mUserState = userState; 319 return this; 320 } 321 322 @NonNull 323 @Override setInstalled(boolean installed)324 public PackageUserStateWrite setInstalled(boolean installed) { 325 if (mUserState != null) { 326 mUserState.setInstalled(installed); 327 } 328 return this; 329 } 330 331 @NonNull 332 @Override setUninstallReason(int reason)333 public PackageUserStateWrite setUninstallReason(int reason) { 334 if (mUserState != null) { 335 mUserState.setUninstallReason(reason); 336 } 337 return this; 338 } 339 340 @NonNull 341 @Override setDistractionFlags( @ackageManager.DistractionRestriction int restrictionFlags)342 public PackageUserStateWrite setDistractionFlags( 343 @PackageManager.DistractionRestriction int restrictionFlags) { 344 if (mUserState != null) { 345 mUserState.setDistractionFlags(restrictionFlags); 346 } 347 return this; 348 } 349 350 @NonNull 351 @Override putSuspendParams(@onNull String suspendingPackage, @Nullable SuspendParams suspendParams)352 public PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage, 353 @Nullable SuspendParams suspendParams) { 354 if (mUserState != null) { 355 mUserState.putSuspendParams(suspendingPackage, suspendParams); 356 } 357 return this; 358 } 359 360 @NonNull 361 @Override removeSuspension(@onNull String suspendingPackage)362 public PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage) { 363 if (mUserState != null) { 364 mUserState.removeSuspension(suspendingPackage); 365 } 366 return this; 367 } 368 369 @NonNull 370 @Override setHidden(boolean hidden)371 public PackageUserStateWrite setHidden(boolean hidden) { 372 if (mUserState != null) { 373 mUserState.setHidden(hidden); 374 } 375 return this; 376 } 377 378 @NonNull 379 @Override setStopped(boolean stopped)380 public PackageUserStateWrite setStopped(boolean stopped) { 381 if (mUserState != null) { 382 mUserState.setStopped(stopped); 383 } 384 return this; 385 } 386 387 @NonNull 388 @Override setNotLaunched(boolean notLaunched)389 public PackageUserStateWrite setNotLaunched(boolean notLaunched) { 390 if (mUserState != null) { 391 mUserState.setNotLaunched(notLaunched); 392 } 393 return this; 394 } 395 396 @NonNull 397 @Override setOverlayPaths(@onNull OverlayPaths overlayPaths)398 public PackageUserStateWrite setOverlayPaths(@NonNull OverlayPaths overlayPaths) { 399 if (mUserState != null) { 400 mUserState.setOverlayPaths(overlayPaths); 401 } 402 return this; 403 } 404 405 @NonNull 406 @Override setOverlayPathsForLibrary(@onNull String libraryName, @Nullable OverlayPaths overlayPaths)407 public PackageUserStateWrite setOverlayPathsForLibrary(@NonNull String libraryName, 408 @Nullable OverlayPaths overlayPaths) { 409 if (mUserState != null) { 410 mUserState.setSharedLibraryOverlayPaths(libraryName, overlayPaths); 411 } 412 return this; 413 } 414 415 @NonNull 416 @Override setHarmfulAppWarning(@ullable String warning)417 public PackageUserStateWrite setHarmfulAppWarning(@Nullable String warning) { 418 if (mUserState != null) { 419 mUserState.setHarmfulAppWarning(warning); 420 } 421 return this; 422 } 423 424 @NonNull 425 @Override setSplashScreenTheme(@ullable String theme)426 public PackageUserStateWrite setSplashScreenTheme(@Nullable String theme) { 427 if (mUserState != null) { 428 mUserState.setSplashScreenTheme(theme); 429 } 430 return this; 431 } 432 433 @NonNull 434 @Override setComponentLabelIcon(@onNull ComponentName componentName, @Nullable String nonLocalizedLabel, @Nullable Integer icon)435 public PackageUserStateWrite setComponentLabelIcon(@NonNull ComponentName componentName, 436 @Nullable String nonLocalizedLabel, @Nullable Integer icon) { 437 if (mUserState != null) { 438 mUserState.overrideLabelAndIcon(componentName, nonLocalizedLabel, icon); 439 } 440 return null; 441 } 442 443 @NonNull 444 @Override setMinAspectRatio( @ackageManager.UserMinAspectRatio int aspectRatio)445 public PackageUserStateWrite setMinAspectRatio( 446 @PackageManager.UserMinAspectRatio int aspectRatio) { 447 if (mUserState != null) { 448 mUserState.setMinAspectRatio(aspectRatio); 449 } 450 return this; 451 } 452 } 453 } 454 } 455