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 setUpdateAvailable(boolean updateAvailable)260 public PackageStateWrite setUpdateAvailable(boolean updateAvailable) { 261 if (mState != null) { 262 mState.setUpdateAvailable(updateAvailable); 263 } 264 return this; 265 } 266 267 @NonNull 268 @Override setLoadingProgress(float progress)269 public PackageStateWrite setLoadingProgress(float progress) { 270 if (mState != null) { 271 mState.setLoadingProgress(progress); 272 } 273 return this; 274 } 275 276 @NonNull 277 @Override setLoadingCompletedTime(long loadingCompletedTime)278 public PackageStateWrite setLoadingCompletedTime(long loadingCompletedTime) { 279 if (mState != null) { 280 mState.setLoadingCompletedTime(loadingCompletedTime); 281 } 282 return this; 283 } 284 285 @NonNull 286 @Override setOverrideSeInfo(@ullable String newSeInfo)287 public PackageStateWrite setOverrideSeInfo(@Nullable String newSeInfo) { 288 if (mState != null) { 289 mState.getTransientState().setOverrideSeInfo(newSeInfo); 290 } 291 return this; 292 } 293 294 @NonNull 295 @Override setInstaller(@ullable String installerPackageName, int installerPackageUid)296 public PackageStateWrite setInstaller(@Nullable String installerPackageName, 297 int installerPackageUid) { 298 if (mState != null) { 299 mState.setInstallerPackage(installerPackageName, installerPackageUid); 300 } 301 return this; 302 } 303 304 @NonNull 305 @Override setUpdateOwner(@onNull String updateOwnerPackageName)306 public PackageStateWrite setUpdateOwner(@NonNull String updateOwnerPackageName) { 307 if (mState != null) { 308 mState.setUpdateOwnerPackage(updateOwnerPackageName); 309 } 310 return this; 311 } 312 313 private static class UserStateWriteWrapper implements PackageUserStateWrite { 314 315 @Nullable 316 private PackageUserStateImpl mUserState; 317 setStates(@ullable PackageUserStateImpl userState)318 public UserStateWriteWrapper setStates(@Nullable PackageUserStateImpl userState) { 319 mUserState = userState; 320 return this; 321 } 322 323 @NonNull 324 @Override setInstalled(boolean installed)325 public PackageUserStateWrite setInstalled(boolean installed) { 326 if (mUserState != null) { 327 mUserState.setInstalled(installed); 328 } 329 return this; 330 } 331 332 @NonNull 333 @Override setUninstallReason(int reason)334 public PackageUserStateWrite setUninstallReason(int reason) { 335 if (mUserState != null) { 336 mUserState.setUninstallReason(reason); 337 } 338 return this; 339 } 340 341 @NonNull 342 @Override setDistractionFlags( @ackageManager.DistractionRestriction int restrictionFlags)343 public PackageUserStateWrite setDistractionFlags( 344 @PackageManager.DistractionRestriction int restrictionFlags) { 345 if (mUserState != null) { 346 mUserState.setDistractionFlags(restrictionFlags); 347 } 348 return this; 349 } 350 351 @NonNull 352 @Override putSuspendParams(@onNull UserPackage suspendingPackage, @Nullable SuspendParams suspendParams)353 public PackageUserStateWrite putSuspendParams(@NonNull UserPackage suspendingPackage, 354 @Nullable SuspendParams suspendParams) { 355 if (mUserState != null) { 356 mUserState.putSuspendParams(suspendingPackage, suspendParams); 357 } 358 return this; 359 } 360 361 @NonNull 362 @Override removeSuspension(@onNull UserPackage suspendingPackage)363 public PackageUserStateWrite removeSuspension(@NonNull UserPackage suspendingPackage) { 364 if (mUserState != null) { 365 mUserState.removeSuspension(suspendingPackage); 366 } 367 return this; 368 } 369 370 @NonNull 371 @Override setHidden(boolean hidden)372 public PackageUserStateWrite setHidden(boolean hidden) { 373 if (mUserState != null) { 374 mUserState.setHidden(hidden); 375 } 376 return this; 377 } 378 379 @NonNull 380 @Override setStopped(boolean stopped)381 public PackageUserStateWrite setStopped(boolean stopped) { 382 if (mUserState != null) { 383 mUserState.setStopped(stopped); 384 } 385 return this; 386 } 387 388 @NonNull 389 @Override setNotLaunched(boolean notLaunched)390 public PackageUserStateWrite setNotLaunched(boolean notLaunched) { 391 if (mUserState != null) { 392 mUserState.setNotLaunched(notLaunched); 393 } 394 return this; 395 } 396 397 @NonNull 398 @Override setOverlayPaths(@onNull OverlayPaths overlayPaths)399 public PackageUserStateWrite setOverlayPaths(@NonNull OverlayPaths overlayPaths) { 400 if (mUserState != null) { 401 mUserState.setOverlayPaths(overlayPaths); 402 } 403 return this; 404 } 405 406 @NonNull 407 @Override setOverlayPathsForLibrary(@onNull String libraryName, @Nullable OverlayPaths overlayPaths)408 public PackageUserStateWrite setOverlayPathsForLibrary(@NonNull String libraryName, 409 @Nullable OverlayPaths overlayPaths) { 410 if (mUserState != null) { 411 mUserState.setSharedLibraryOverlayPaths(libraryName, overlayPaths); 412 } 413 return this; 414 } 415 416 @NonNull 417 @Override setHarmfulAppWarning(@ullable String warning)418 public PackageUserStateWrite setHarmfulAppWarning(@Nullable String warning) { 419 if (mUserState != null) { 420 mUserState.setHarmfulAppWarning(warning); 421 } 422 return this; 423 } 424 425 @NonNull 426 @Override setSplashScreenTheme(@ullable String theme)427 public PackageUserStateWrite setSplashScreenTheme(@Nullable String theme) { 428 if (mUserState != null) { 429 mUserState.setSplashScreenTheme(theme); 430 } 431 return this; 432 } 433 434 @NonNull 435 @Override setComponentLabelIcon(@onNull ComponentName componentName, @Nullable String nonLocalizedLabel, @Nullable Integer icon)436 public PackageUserStateWrite setComponentLabelIcon(@NonNull ComponentName componentName, 437 @Nullable String nonLocalizedLabel, @Nullable Integer icon) { 438 if (mUserState != null) { 439 mUserState.overrideLabelAndIcon(componentName, nonLocalizedLabel, icon); 440 } 441 return null; 442 } 443 444 @NonNull 445 @Override setMinAspectRatio( @ackageManager.UserMinAspectRatio int aspectRatio)446 public PackageUserStateWrite setMinAspectRatio( 447 @PackageManager.UserMinAspectRatio int aspectRatio) { 448 if (mUserState != null) { 449 mUserState.setMinAspectRatio(aspectRatio); 450 } 451 return this; 452 } 453 } 454 } 455 } 456