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