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