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.apphibernation; 18 19 import static android.app.AppOpsManager.OP_NONE; 20 import static android.content.Intent.ACTION_PACKAGE_ADDED; 21 import static android.content.Intent.ACTION_PACKAGE_REMOVED; 22 import static android.content.Intent.EXTRA_REMOVED_FOR_ALL_USERS; 23 import static android.content.Intent.EXTRA_REPLACING; 24 import static android.content.pm.PackageManager.MATCH_ANY_USER; 25 import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION; 26 27 import static com.android.server.apphibernation.AppHibernationConstants.KEY_APP_HIBERNATION_ENABLED; 28 29 import android.Manifest; 30 import android.annotation.NonNull; 31 import android.annotation.Nullable; 32 import android.app.Activity; 33 import android.app.ActivityManager; 34 import android.app.ActivityThread; 35 import android.app.IActivityManager; 36 import android.app.StatsManager; 37 import android.app.StatsManager.StatsPullAtomCallback; 38 import android.app.usage.StorageStats; 39 import android.app.usage.StorageStatsManager; 40 import android.app.usage.UsageEvents; 41 import android.app.usage.UsageStatsManagerInternal; 42 import android.app.usage.UsageStatsManagerInternal.UsageEventListener; 43 import android.apphibernation.HibernationStats; 44 import android.apphibernation.IAppHibernationService; 45 import android.content.BroadcastReceiver; 46 import android.content.Context; 47 import android.content.Intent; 48 import android.content.IntentFilter; 49 import android.content.pm.ApplicationInfo; 50 import android.content.pm.IPackageManager; 51 import android.content.pm.PackageInfo; 52 import android.content.pm.PackageManager; 53 import android.content.pm.PackageManagerInternal; 54 import android.content.pm.UserInfo; 55 import android.os.Binder; 56 import android.os.Environment; 57 import android.os.RemoteException; 58 import android.os.ResultReceiver; 59 import android.os.ServiceManager; 60 import android.os.ShellCallback; 61 import android.os.Trace; 62 import android.os.UserHandle; 63 import android.os.UserManager; 64 import android.provider.DeviceConfig; 65 import android.provider.DeviceConfig.Properties; 66 import android.text.TextUtils; 67 import android.util.ArrayMap; 68 import android.util.ArraySet; 69 import android.util.Slog; 70 import android.util.SparseArray; 71 import android.util.StatsEvent; 72 73 import com.android.internal.annotations.GuardedBy; 74 import com.android.internal.annotations.VisibleForTesting; 75 import com.android.internal.util.DumpUtils; 76 import com.android.internal.util.FrameworkStatsLog; 77 import com.android.internal.util.IndentingPrintWriter; 78 import com.android.server.LocalServices; 79 import com.android.server.SystemService; 80 81 import java.io.File; 82 import java.io.FileDescriptor; 83 import java.io.IOException; 84 import java.io.PrintWriter; 85 import java.util.ArrayList; 86 import java.util.List; 87 import java.util.Map; 88 import java.util.Set; 89 import java.util.concurrent.Executor; 90 import java.util.concurrent.Executors; 91 import java.util.concurrent.ScheduledExecutorService; 92 93 /** 94 * System service that manages app hibernation state, a state apps can enter that means they are 95 * not being actively used and can be optimized for storage. The actual policy for determining 96 * if an app should hibernate is managed by PermissionController code. 97 */ 98 public final class AppHibernationService extends SystemService { 99 private static final String TAG = "AppHibernationService"; 100 private static final long PACKAGE_MATCH_FLAGS = 101 PackageManager.MATCH_DIRECT_BOOT_AWARE 102 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 103 | PackageManager.MATCH_UNINSTALLED_PACKAGES 104 | PackageManager.MATCH_DISABLED_COMPONENTS 105 | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS 106 | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS; 107 108 /** 109 * Lock for accessing any in-memory hibernation state 110 */ 111 private final Object mLock = new Object(); 112 private final Context mContext; 113 private final IPackageManager mIPackageManager; 114 private final PackageManagerInternal mPackageManagerInternal; 115 private final IActivityManager mIActivityManager; 116 private final UserManager mUserManager; 117 private final StorageStatsManager mStorageStatsManager; 118 119 @GuardedBy("mLock") 120 private final SparseArray<Map<String, UserLevelState>> mUserStates = new SparseArray<>(); 121 private final SparseArray<HibernationStateDiskStore<UserLevelState>> mUserDiskStores = 122 new SparseArray<>(); 123 @GuardedBy("mLock") 124 private final Map<String, GlobalLevelState> mGlobalHibernationStates = new ArrayMap<>(); 125 private final HibernationStateDiskStore<GlobalLevelState> mGlobalLevelHibernationDiskStore; 126 private final Injector mInjector; 127 private final Executor mBackgroundExecutor; 128 private final boolean mOatArtifactDeletionEnabled; 129 130 @VisibleForTesting 131 public static boolean sIsServiceEnabled; 132 133 /** 134 * Initializes the system service. 135 * <p> 136 * Subclasses must define a single argument constructor that accepts the context 137 * and passes it to super. 138 * </p> 139 * 140 * @param context The system server context. 141 */ AppHibernationService(@onNull Context context)142 public AppHibernationService(@NonNull Context context) { 143 this(new InjectorImpl(context)); 144 } 145 146 @VisibleForTesting AppHibernationService(@onNull Injector injector)147 AppHibernationService(@NonNull Injector injector) { 148 super(injector.getContext()); 149 mContext = injector.getContext(); 150 mIPackageManager = injector.getPackageManager(); 151 mPackageManagerInternal = injector.getPackageManagerInternal(); 152 mIActivityManager = injector.getActivityManager(); 153 mUserManager = injector.getUserManager(); 154 mStorageStatsManager = injector.getStorageStatsManager(); 155 mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore(); 156 mBackgroundExecutor = injector.getBackgroundExecutor(); 157 mOatArtifactDeletionEnabled = injector.isOatArtifactDeletionEnabled(); 158 mInjector = injector; 159 160 final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */); 161 162 IntentFilter intentFilter = new IntentFilter(); 163 intentFilter.addAction(ACTION_PACKAGE_ADDED); 164 intentFilter.addAction(ACTION_PACKAGE_REMOVED); 165 intentFilter.addDataScheme("package"); 166 userAllContext.registerReceiver(mBroadcastReceiver, intentFilter); 167 LocalServices.addService(AppHibernationManagerInternal.class, mLocalService); 168 mInjector.getUsageStatsManagerInternal().registerListener(mUsageEventListener); 169 } 170 171 @Override onStart()172 public void onStart() { 173 publishBinderService(Context.APP_HIBERNATION_SERVICE, mServiceStub); 174 } 175 176 @Override onBootPhase(int phase)177 public void onBootPhase(int phase) { 178 if (phase == PHASE_BOOT_COMPLETED) { 179 mBackgroundExecutor.execute(() -> { 180 List<GlobalLevelState> states = 181 mGlobalLevelHibernationDiskStore.readHibernationStates(); 182 synchronized (mLock) { 183 initializeGlobalHibernationStates(states); 184 } 185 }); 186 } 187 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 188 sIsServiceEnabled = isDeviceConfigAppHibernationEnabled(); 189 DeviceConfig.addOnPropertiesChangedListener( 190 NAMESPACE_APP_HIBERNATION, 191 ActivityThread.currentApplication().getMainExecutor(), 192 this::onDeviceConfigChanged); 193 final StatsManager statsManager = getContext().getSystemService(StatsManager.class); 194 final StatsPullAtomCallbackImpl pullAtomCallback = new StatsPullAtomCallbackImpl(); 195 statsManager.setPullAtomCallback( 196 FrameworkStatsLog.USER_LEVEL_HIBERNATED_APPS, 197 /* metadata */ null, // use default PullAtomMetadata values 198 mBackgroundExecutor, 199 pullAtomCallback); 200 statsManager.setPullAtomCallback( 201 FrameworkStatsLog.GLOBAL_HIBERNATED_APPS, 202 /* metadata */ null, // use default PullAtomMetadata values 203 mBackgroundExecutor, 204 pullAtomCallback); 205 } 206 } 207 208 /** 209 * Whether global hibernation should delete ART ahead-of-time compilation artifacts and prevent 210 * package manager from re-optimizing the APK. 211 */ isOatArtifactDeletionEnabled()212 private boolean isOatArtifactDeletionEnabled() { 213 getContext().enforceCallingOrSelfPermission( 214 android.Manifest.permission.MANAGE_APP_HIBERNATION, 215 "Caller does not have MANAGE_APP_HIBERNATION permission."); 216 return mOatArtifactDeletionEnabled; 217 } 218 219 /** 220 * Whether a package is hibernating for a given user. 221 * 222 * @param packageName the package to check 223 * @param userId the user to check 224 * @return true if package is hibernating for the user 225 */ isHibernatingForUser(String packageName, int userId)226 boolean isHibernatingForUser(String packageName, int userId) { 227 String methodName = "isHibernatingForUser"; 228 if (!sIsServiceEnabled) { 229 return false; 230 } 231 getContext().enforceCallingOrSelfPermission( 232 android.Manifest.permission.MANAGE_APP_HIBERNATION, 233 "Caller did not have permission while calling " + methodName); 234 userId = handleIncomingUser(userId, methodName); 235 synchronized (mLock) { 236 // Don't log as this method can be called before user states exist as part of the 237 // force-stop check. 238 if (!checkUserStatesExist(userId, methodName, /* shouldLog= */ false)) { 239 return false; 240 } 241 final Map<String, UserLevelState> packageStates = mUserStates.get(userId); 242 final UserLevelState pkgState = packageStates.get(packageName); 243 if (pkgState == null 244 || !mPackageManagerInternal.canQueryPackage( 245 Binder.getCallingUid(), packageName)) { 246 return false; 247 } 248 return pkgState.hibernated; 249 } 250 } 251 252 /** 253 * Whether a package is hibernated globally. This only occurs when a package is hibernating for 254 * all users and allows us to make optimizations at the package or APK level. 255 * 256 * @param packageName package to check 257 */ isHibernatingGlobally(String packageName)258 boolean isHibernatingGlobally(String packageName) { 259 if (!sIsServiceEnabled) { 260 return false; 261 } 262 getContext().enforceCallingOrSelfPermission( 263 android.Manifest.permission.MANAGE_APP_HIBERNATION, 264 "Caller does not have MANAGE_APP_HIBERNATION permission."); 265 synchronized (mLock) { 266 GlobalLevelState state = mGlobalHibernationStates.get(packageName); 267 if (state == null 268 || !mPackageManagerInternal.canQueryPackage( 269 Binder.getCallingUid(), packageName)) { 270 // This API can be legitimately called before installation finishes as part of 271 // dex optimization, so we just return false here. 272 return false; 273 } 274 return state.hibernated; 275 } 276 } 277 278 /** 279 * Set whether the package is hibernating for the given user. 280 * 281 * @param packageName package to modify state 282 * @param userId user 283 * @param isHibernating new hibernation state 284 */ setHibernatingForUser(String packageName, int userId, boolean isHibernating)285 void setHibernatingForUser(String packageName, int userId, boolean isHibernating) { 286 String methodName = "setHibernatingForUser"; 287 if (!sIsServiceEnabled) { 288 return; 289 } 290 getContext().enforceCallingOrSelfPermission( 291 android.Manifest.permission.MANAGE_APP_HIBERNATION, 292 "Caller does not have MANAGE_APP_HIBERNATION permission."); 293 final int realUserId = handleIncomingUser(userId, methodName); 294 synchronized (mLock) { 295 if (!checkUserStatesExist(realUserId, methodName, /* shouldLog= */ true)) { 296 return; 297 } 298 final Map<String, UserLevelState> packageStates = mUserStates.get(realUserId); 299 final UserLevelState pkgState = packageStates.get(packageName); 300 if (pkgState == null 301 || !mPackageManagerInternal.canQueryPackage( 302 Binder.getCallingUid(), packageName)) { 303 Slog.e(TAG, TextUtils.formatSimple("Package %s is not installed for user %s", 304 packageName, realUserId)); 305 return; 306 } 307 308 if (pkgState.hibernated == isHibernating) { 309 return; 310 } 311 312 pkgState.hibernated = isHibernating; 313 if (isHibernating) { 314 mBackgroundExecutor.execute( 315 () -> hibernatePackageForUser(packageName, realUserId, pkgState)); 316 } else { 317 mBackgroundExecutor.execute( 318 () -> unhibernatePackageForUser(packageName, realUserId)); 319 pkgState.lastUnhibernatedMs = System.currentTimeMillis(); 320 } 321 322 final UserLevelState stateSnapshot = new UserLevelState(pkgState); 323 final int userIdSnapshot = realUserId; 324 mBackgroundExecutor.execute(() -> { 325 FrameworkStatsLog.write( 326 FrameworkStatsLog.USER_LEVEL_HIBERNATION_STATE_CHANGED, 327 stateSnapshot.packageName, 328 userIdSnapshot, 329 stateSnapshot.hibernated); 330 }); 331 List<UserLevelState> states = new ArrayList<>(mUserStates.get(realUserId).values()); 332 mUserDiskStores.get(realUserId).scheduleWriteHibernationStates(states); 333 } 334 } 335 336 /** 337 * Set whether the package should be hibernated globally at a package level, allowing the 338 * the system to make optimizations at the package or APK level. 339 * 340 * @param packageName package to hibernate globally 341 * @param isHibernating new hibernation state 342 */ setHibernatingGlobally(String packageName, boolean isHibernating)343 void setHibernatingGlobally(String packageName, boolean isHibernating) { 344 if (!sIsServiceEnabled) { 345 return; 346 } 347 getContext().enforceCallingOrSelfPermission( 348 android.Manifest.permission.MANAGE_APP_HIBERNATION, 349 "Caller does not have MANAGE_APP_HIBERNATION permission."); 350 synchronized (mLock) { 351 GlobalLevelState state = mGlobalHibernationStates.get(packageName); 352 if (state == null 353 || !mPackageManagerInternal.canQueryPackage( 354 Binder.getCallingUid(), packageName)) { 355 Slog.e(TAG, TextUtils.formatSimple( 356 "Package %s is not installed for any user", packageName)); 357 return; 358 } 359 if (state.hibernated != isHibernating) { 360 state.hibernated = isHibernating; 361 if (isHibernating) { 362 mBackgroundExecutor.execute(() -> hibernatePackageGlobally(packageName, state)); 363 } else { 364 state.savedByte = 0; 365 state.lastUnhibernatedMs = System.currentTimeMillis(); 366 } 367 List<GlobalLevelState> states = new ArrayList<>(mGlobalHibernationStates.values()); 368 mGlobalLevelHibernationDiskStore.scheduleWriteHibernationStates(states); 369 } 370 } 371 } 372 373 /** 374 * Get the hibernating packages for the given user. This is equivalent to the list of 375 * packages for the user that return true for {@link #isHibernatingForUser}. 376 */ getHibernatingPackagesForUser(int userId)377 @NonNull List<String> getHibernatingPackagesForUser(int userId) { 378 ArrayList<String> hibernatingPackages = new ArrayList<>(); 379 String methodName = "getHibernatingPackagesForUser"; 380 if (!sIsServiceEnabled) { 381 return hibernatingPackages; 382 } 383 getContext().enforceCallingOrSelfPermission( 384 android.Manifest.permission.MANAGE_APP_HIBERNATION, 385 "Caller does not have MANAGE_APP_HIBERNATION permission."); 386 userId = handleIncomingUser(userId, methodName); 387 synchronized (mLock) { 388 if (!checkUserStatesExist(userId, methodName, /* shouldLog= */ true)) { 389 return hibernatingPackages; 390 } 391 Map<String, UserLevelState> userStates = mUserStates.get(userId); 392 for (UserLevelState state : userStates.values()) { 393 String packageName = state.packageName; 394 if (!mPackageManagerInternal.canQueryPackage( 395 Binder.getCallingUid(), packageName)) { 396 // Package is not visible to caller 397 continue; 398 } 399 if (state.hibernated) { 400 hibernatingPackages.add(state.packageName); 401 } 402 } 403 return hibernatingPackages; 404 } 405 } 406 407 /** 408 * Return the stats from app hibernation for each package provided. 409 * 410 * @param packageNames the set of packages to return stats for. Returns all if null 411 * @return map from package to stats for that package 412 */ getHibernationStatsForUser( @ullable Set<String> packageNames, int userId)413 public Map<String, HibernationStats> getHibernationStatsForUser( 414 @Nullable Set<String> packageNames, int userId) { 415 Map<String, HibernationStats> statsMap = new ArrayMap<>(); 416 String methodName = "getHibernationStatsForUser"; 417 if (!sIsServiceEnabled) { 418 return statsMap; 419 } 420 getContext().enforceCallingOrSelfPermission( 421 android.Manifest.permission.MANAGE_APP_HIBERNATION, 422 "Caller does not have MANAGE_APP_HIBERNATION permission."); 423 userId = handleIncomingUser(userId, methodName); 424 synchronized (mLock) { 425 if (!checkUserStatesExist(userId, methodName, /* shouldLog= */ true)) { 426 return statsMap; 427 } 428 final Map<String, UserLevelState> userPackageStates = mUserStates.get(userId); 429 Set<String> pkgs = packageNames != null ? packageNames : userPackageStates.keySet(); 430 for (String pkgName : pkgs) { 431 if (!mPackageManagerInternal.canQueryPackage(Binder.getCallingUid(), pkgName)) { 432 // Package not visible to caller 433 continue; 434 } 435 if (!mGlobalHibernationStates.containsKey(pkgName) 436 || !userPackageStates.containsKey(pkgName)) { 437 Slog.w(TAG, TextUtils.formatSimple( 438 "No hibernation state associated with package %s user %d. Maybe" 439 + "the package was uninstalled? ", pkgName, userId)); 440 continue; 441 } 442 long diskBytesSaved = mGlobalHibernationStates.get(pkgName).savedByte 443 + userPackageStates.get(pkgName).savedByte; 444 HibernationStats stats = new HibernationStats(diskBytesSaved); 445 statsMap.put(pkgName, stats); 446 } 447 } 448 return statsMap; 449 } 450 451 /** 452 * Put an app into hibernation for a given user, allowing user-level optimizations to occur. Do 453 * not hold {@link #mLock} while calling this to avoid deadlock scenarios. 454 */ hibernatePackageForUser(@onNull String packageName, int userId, UserLevelState state)455 private void hibernatePackageForUser(@NonNull String packageName, int userId, 456 UserLevelState state) { 457 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage"); 458 final long caller = Binder.clearCallingIdentity(); 459 try { 460 ApplicationInfo info = mIPackageManager.getApplicationInfo( 461 packageName, PACKAGE_MATCH_FLAGS, userId); 462 StorageStats stats = mStorageStatsManager.queryStatsForPackage( 463 info.storageUuid, packageName, new UserHandle(userId)); 464 if (android.app.Flags.appRestrictionsApi()) { 465 noteHibernationChange(packageName, info.uid, true); 466 } 467 mIActivityManager.forceStopPackage(packageName, userId); 468 mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId, 469 null /* observer */); 470 synchronized (mLock) { 471 state.savedByte = stats.getCacheBytes(); 472 } 473 } catch (RemoteException e) { 474 throw new IllegalStateException( 475 "Failed to hibernate due to manager not being available", e); 476 } catch (PackageManager.NameNotFoundException e) { 477 Slog.e(TAG, "Package name not found when querying storage stats", e); 478 } catch (IOException e) { 479 Slog.e(TAG, "Storage device not found", e); 480 } finally { 481 Binder.restoreCallingIdentity(caller); 482 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 483 } 484 } 485 486 /** 487 * Remove a package from hibernation for a given user. Do not hold {@link #mLock} while calling 488 * this. 489 */ unhibernatePackageForUser(@onNull String packageName, int userId)490 private void unhibernatePackageForUser(@NonNull String packageName, int userId) { 491 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage"); 492 final long caller = Binder.clearCallingIdentity(); 493 // Deliver LOCKED_BOOT_COMPLETE AND BOOT_COMPLETE broadcast so app can re-register 494 // their alarms/jobs/etc. 495 try { 496 if (android.app.Flags.appRestrictionsApi()) { 497 ApplicationInfo info = mIPackageManager.getApplicationInfo( 498 packageName, PACKAGE_MATCH_FLAGS, userId); 499 noteHibernationChange(packageName, info.uid, false); 500 } 501 Intent lockedBcIntent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED) 502 .setPackage(packageName); 503 final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED}; 504 mIActivityManager.broadcastIntentWithFeature( 505 null /* caller */, 506 null /* callingFeatureId */, 507 lockedBcIntent, 508 null /* resolvedType */, 509 null /* resultTo */, 510 Activity.RESULT_OK, 511 null /* resultData */, 512 null /* resultExtras */, 513 requiredPermissions, 514 null /* excludedPermissions */, 515 null /* excludedPackages */, 516 OP_NONE, 517 null /* bOptions */, 518 false /* serialized */, 519 false /* sticky */, 520 userId); 521 522 Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName); 523 mIActivityManager.broadcastIntentWithFeature( 524 null /* caller */, 525 null /* callingFeatureId */, 526 bcIntent, 527 null /* resolvedType */, 528 null /* resultTo */, 529 Activity.RESULT_OK, 530 null /* resultData */, 531 null /* resultExtras */, 532 requiredPermissions, 533 null /* excludedPermissions */, 534 null /* excludedPackages */, 535 OP_NONE, 536 null /* bOptions */, 537 false /* serialized */, 538 false /* sticky */, 539 userId); 540 } catch (RemoteException e) { 541 throw e.rethrowFromSystemServer(); 542 } finally { 543 Binder.restoreCallingIdentity(caller); 544 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 545 } 546 } 547 548 /** 549 * Put a package into global hibernation, optimizing its storage at a package / APK level. Do 550 * not hold {@link #mLock} while calling this. 551 */ hibernatePackageGlobally(@onNull String packageName, GlobalLevelState state)552 private void hibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) { 553 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally"); 554 long savedBytes = 0; 555 if (mOatArtifactDeletionEnabled) { 556 savedBytes = Math.max( 557 mPackageManagerInternal.deleteOatArtifactsOfPackage(packageName), 558 0); 559 } 560 synchronized (mLock) { 561 state.savedByte = savedBytes; 562 } 563 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 564 } 565 566 /** Inform ActivityManager that the app being stopped or unstopped due to hibernation */ noteHibernationChange(String packageName, int uid, boolean hibernated)567 private void noteHibernationChange(String packageName, int uid, boolean hibernated) { 568 try { 569 if (hibernated) { 570 // TODO: Switch to an ActivityManagerInternal API 571 mIActivityManager.noteAppRestrictionEnabled( 572 packageName, uid, ActivityManager.RESTRICTION_LEVEL_FORCE_STOPPED, 573 true, ActivityManager.RESTRICTION_REASON_DORMANT, null, 574 ActivityManager.RESTRICTION_SOURCE_SYSTEM, 575 /* TODO: fetch actual timeout - 90 days */ 90 * 24 * 60 * 60_000L); 576 } 577 // No need to log the unhibernate case as an unstop is logged already in ActivityMS 578 } catch (RemoteException e) { 579 Slog.e(TAG, "Couldn't set restriction state change"); 580 } 581 } 582 583 /** 584 * Initializes in-memory store of user-level hibernation states for the given user 585 * 586 * @param userId user id to add installed packages for 587 * @param diskStates states pulled from disk, if available 588 */ 589 @GuardedBy("mLock") initializeUserHibernationStates(int userId, @Nullable List<UserLevelState> diskStates)590 private void initializeUserHibernationStates(int userId, 591 @Nullable List<UserLevelState> diskStates) { 592 List<PackageInfo> packages; 593 try { 594 packages = mIPackageManager.getInstalledPackages(PACKAGE_MATCH_FLAGS, userId).getList(); 595 } catch (RemoteException e) { 596 throw new IllegalStateException("Package manager not available", e); 597 } 598 599 Map<String, UserLevelState> userLevelStates = new ArrayMap<>(); 600 601 for (int i = 0, size = packages.size(); i < size; i++) { 602 String packageName = packages.get(i).packageName; 603 UserLevelState state = new UserLevelState(); 604 state.packageName = packageName; 605 userLevelStates.put(packageName, state); 606 } 607 608 if (diskStates != null) { 609 Map<String, PackageInfo> installedPackages = new ArrayMap<>(); 610 for (int i = 0, size = packages.size(); i < size; i++) { 611 installedPackages.put(packages.get(i).packageName, packages.get(i)); 612 } 613 for (int i = 0, size = diskStates.size(); i < size; i++) { 614 String packageName = diskStates.get(i).packageName; 615 PackageInfo pkgInfo = installedPackages.get(packageName); 616 UserLevelState currentState = diskStates.get(i); 617 if (pkgInfo == null) { 618 Slog.w(TAG, TextUtils.formatSimple( 619 "No hibernation state associated with package %s user %d. Maybe" 620 + "the package was uninstalled? ", packageName, userId)); 621 continue; 622 } 623 if (pkgInfo.applicationInfo != null 624 && (pkgInfo.applicationInfo.flags &= ApplicationInfo.FLAG_STOPPED) == 0 625 && currentState.hibernated) { 626 // App is not stopped but is hibernated. Disk state is stale, so unhibernate 627 // the app. 628 currentState.hibernated = false; 629 currentState.lastUnhibernatedMs = System.currentTimeMillis(); 630 } 631 userLevelStates.put(packageName, currentState); 632 } 633 } 634 mUserStates.put(userId, userLevelStates); 635 } 636 637 /** 638 * Initialize in-memory store of global level hibernation states. 639 * 640 * @param diskStates global level hibernation states pulled from disk, if available 641 */ 642 @GuardedBy("mLock") initializeGlobalHibernationStates(@ullable List<GlobalLevelState> diskStates)643 private void initializeGlobalHibernationStates(@Nullable List<GlobalLevelState> diskStates) { 644 List<PackageInfo> packages; 645 try { 646 packages = mIPackageManager.getInstalledPackages( 647 PACKAGE_MATCH_FLAGS | MATCH_ANY_USER, 0 /* userId */).getList(); 648 } catch (RemoteException e) { 649 throw new IllegalStateException("Package manager not available", e); 650 } 651 652 for (int i = 0, size = packages.size(); i < size; i++) { 653 String packageName = packages.get(i).packageName; 654 GlobalLevelState state = new GlobalLevelState(); 655 state.packageName = packageName; 656 mGlobalHibernationStates.put(packageName, state); 657 } 658 if (diskStates != null) { 659 Set<String> installedPackages = new ArraySet<>(); 660 for (int i = 0, size = packages.size(); i < size; i++) { 661 installedPackages.add(packages.get(i).packageName); 662 } 663 for (int i = 0, size = diskStates.size(); i < size; i++) { 664 GlobalLevelState state = diskStates.get(i); 665 if (!installedPackages.contains(state.packageName)) { 666 Slog.w(TAG, TextUtils.formatSimple( 667 "No hibernation state associated with package %s. Maybe the " 668 + "package was uninstalled? ", state.packageName)); 669 continue; 670 } 671 mGlobalHibernationStates.put(state.packageName, state); 672 } 673 } 674 } 675 676 @Override onUserUnlocking(@onNull TargetUser user)677 public void onUserUnlocking(@NonNull TargetUser user) { 678 int userId = user.getUserIdentifier(); 679 HibernationStateDiskStore<UserLevelState> diskStore = 680 mInjector.getUserLevelDiskStore(userId); 681 mUserDiskStores.put(userId, diskStore); 682 mBackgroundExecutor.execute(() -> { 683 List<UserLevelState> storedStates = diskStore.readHibernationStates(); 684 synchronized (mLock) { 685 // Ensure user hasn't stopped in the time to execute. 686 if (mUserManager.isUserUnlockingOrUnlocked(userId)) { 687 initializeUserHibernationStates(userId, storedStates); 688 // Globally unhibernate a package if the unlocked user does not have it 689 // hibernated. 690 for (UserLevelState userState : mUserStates.get(userId).values()) { 691 String pkgName = userState.packageName; 692 GlobalLevelState globalState = mGlobalHibernationStates.get(pkgName); 693 if (globalState.hibernated && !userState.hibernated) { 694 setHibernatingGlobally(pkgName, false); 695 } 696 } 697 } 698 } 699 }); 700 } 701 702 @Override onUserStopping(@onNull TargetUser user)703 public void onUserStopping(@NonNull TargetUser user) { 704 int userId = user.getUserIdentifier(); 705 // TODO: Flush any scheduled writes to disk immediately on user stopping / power off. 706 synchronized (mLock) { 707 mUserDiskStores.remove(userId); 708 mUserStates.remove(userId); 709 } 710 } 711 onPackageAdded(@onNull String packageName, int userId)712 private void onPackageAdded(@NonNull String packageName, int userId) { 713 synchronized (mLock) { 714 if (!mUserStates.contains(userId)) { 715 return; 716 } 717 UserLevelState userState = new UserLevelState(); 718 userState.packageName = packageName; 719 mUserStates.get(userId).put(packageName, userState); 720 if (!mGlobalHibernationStates.containsKey(packageName)) { 721 GlobalLevelState globalState = new GlobalLevelState(); 722 globalState.packageName = packageName; 723 mGlobalHibernationStates.put(packageName, globalState); 724 } 725 } 726 } 727 onPackageRemoved(@onNull String packageName, int userId)728 private void onPackageRemoved(@NonNull String packageName, int userId) { 729 synchronized (mLock) { 730 if (!mUserStates.contains(userId)) { 731 return; 732 } 733 mUserStates.get(userId).remove(packageName); 734 } 735 } 736 onPackageRemovedForAllUsers(@onNull String packageName)737 private void onPackageRemovedForAllUsers(@NonNull String packageName) { 738 synchronized (mLock) { 739 mGlobalHibernationStates.remove(packageName); 740 } 741 } 742 onDeviceConfigChanged(Properties properties)743 private void onDeviceConfigChanged(Properties properties) { 744 for (String key : properties.getKeyset()) { 745 if (TextUtils.equals(KEY_APP_HIBERNATION_ENABLED, key)) { 746 sIsServiceEnabled = isDeviceConfigAppHibernationEnabled(); 747 Slog.d(TAG, "App hibernation changed to enabled=" + sIsServiceEnabled); 748 break; 749 } 750 } 751 } 752 753 /** 754 * Private helper method to get the real user id and enforce permission checks. 755 * 756 * @param userId user id to handle 757 * @param name name to use for exceptions 758 * @return real user id 759 */ handleIncomingUser(int userId, @NonNull String name)760 private int handleIncomingUser(int userId, @NonNull String name) { 761 int callingUid = Binder.getCallingUid(); 762 try { 763 return mIActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid, userId, 764 false /* allowAll */, true /* requireFull */, name, null); 765 } catch (RemoteException re) { 766 throw re.rethrowFromSystemServer(); 767 } 768 } 769 770 /** 771 * Check that user states exist. 772 * 773 * @param userId user to check 774 * @param methodName method name that is calling. Used for logging purposes. 775 * @param shouldLog whether we should log why the user state doesn't exist 776 * @return true if user states exist 777 */ 778 @GuardedBy("mLock") checkUserStatesExist(int userId, String methodName, boolean shouldLog)779 private boolean checkUserStatesExist(int userId, String methodName, boolean shouldLog) { 780 if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { 781 if (shouldLog) { 782 Slog.w(TAG, TextUtils.formatSimple( 783 "Attempt to call %s on stopped or nonexistent user %d", 784 methodName, userId)); 785 } 786 return false; 787 } 788 if (!mUserStates.contains(userId)) { 789 if (shouldLog) { 790 Slog.w(TAG, TextUtils.formatSimple( 791 "Attempt to call %s before states have been read from disk", methodName)); 792 } 793 return false; 794 } 795 return true; 796 } 797 dump(PrintWriter pw)798 private void dump(PrintWriter pw) { 799 // Check usage stats permission since hibernation indirectly informs usage. 800 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return; 801 802 IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " "); 803 804 synchronized (mLock) { 805 final int userCount = mUserStates.size(); 806 for (int i = 0; i < userCount; i++) { 807 final int userId = mUserStates.keyAt(i); 808 idpw.print("User Level Hibernation States, "); 809 idpw.printPair("user", userId); 810 idpw.println(); 811 Map<String, UserLevelState> stateMap = mUserStates.get(userId); 812 idpw.increaseIndent(); 813 for (UserLevelState state : stateMap.values()) { 814 idpw.print(state); 815 idpw.println(); 816 } 817 idpw.decreaseIndent(); 818 } 819 idpw.println(); 820 idpw.print("Global Level Hibernation States"); 821 idpw.println(); 822 for (GlobalLevelState state : mGlobalHibernationStates.values()) { 823 idpw.print(state); 824 idpw.println(); 825 } 826 } 827 } 828 829 private final AppHibernationManagerInternal mLocalService = new LocalService(this); 830 831 private static final class LocalService extends AppHibernationManagerInternal { 832 private final AppHibernationService mService; 833 LocalService(AppHibernationService service)834 LocalService(AppHibernationService service) { 835 mService = service; 836 } 837 838 @Override isHibernatingForUser(String packageName, int userId)839 public boolean isHibernatingForUser(String packageName, int userId) { 840 return mService.isHibernatingForUser(packageName, userId); 841 } 842 843 @Override setHibernatingForUser(String packageName, int userId, boolean isHibernating)844 public void setHibernatingForUser(String packageName, int userId, boolean isHibernating) { 845 mService.setHibernatingForUser(packageName, userId, isHibernating); 846 } 847 848 @Override setHibernatingGlobally(String packageName, boolean isHibernating)849 public void setHibernatingGlobally(String packageName, boolean isHibernating) { 850 mService.setHibernatingGlobally(packageName, isHibernating); 851 } 852 853 @Override isHibernatingGlobally(String packageName)854 public boolean isHibernatingGlobally(String packageName) { 855 return mService.isHibernatingGlobally(packageName); 856 } 857 858 @Override isOatArtifactDeletionEnabled()859 public boolean isOatArtifactDeletionEnabled() { 860 return mService.isOatArtifactDeletionEnabled(); 861 } 862 } 863 864 private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this); 865 866 static final class AppHibernationServiceStub extends IAppHibernationService.Stub { 867 final AppHibernationService mService; 868 AppHibernationServiceStub(AppHibernationService service)869 AppHibernationServiceStub(AppHibernationService service) { 870 mService = service; 871 } 872 873 @Override isHibernatingForUser(String packageName, int userId)874 public boolean isHibernatingForUser(String packageName, int userId) { 875 return mService.isHibernatingForUser(packageName, userId); 876 } 877 878 @Override setHibernatingForUser(String packageName, int userId, boolean isHibernating)879 public void setHibernatingForUser(String packageName, int userId, boolean isHibernating) { 880 mService.setHibernatingForUser(packageName, userId, isHibernating); 881 } 882 883 @Override setHibernatingGlobally(String packageName, boolean isHibernating)884 public void setHibernatingGlobally(String packageName, boolean isHibernating) { 885 mService.setHibernatingGlobally(packageName, isHibernating); 886 } 887 888 @Override isHibernatingGlobally(String packageName)889 public boolean isHibernatingGlobally(String packageName) { 890 return mService.isHibernatingGlobally(packageName); 891 } 892 893 @Override getHibernatingPackagesForUser(int userId)894 public List<String> getHibernatingPackagesForUser(int userId) { 895 return mService.getHibernatingPackagesForUser(userId); 896 } 897 898 @Override getHibernationStatsForUser( @ullable List<String> packageNames, int userId)899 public Map<String, HibernationStats> getHibernationStatsForUser( 900 @Nullable List<String> packageNames, int userId) { 901 Set<String> pkgsSet = packageNames != null ? new ArraySet<>(packageNames) : null; 902 return mService.getHibernationStatsForUser(pkgsSet, userId); 903 } 904 905 @Override isOatArtifactDeletionEnabled()906 public boolean isOatArtifactDeletionEnabled() { 907 return mService.isOatArtifactDeletionEnabled(); 908 } 909 910 @Override onShellCommand(@ullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver)911 public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, 912 @Nullable FileDescriptor err, @NonNull String[] args, 913 @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) { 914 new AppHibernationShellCommand(mService).exec(this, in, out, err, args, callback, 915 resultReceiver); 916 } 917 918 @Override dump(@onNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args)919 protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, 920 @Nullable String[] args) { 921 mService.dump(fout); 922 } 923 } 924 925 // Broadcast receiver for package add/removal events 926 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 927 @Override 928 public void onReceive(Context context, Intent intent) { 929 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 930 if (userId == UserHandle.USER_NULL) { 931 return; 932 } 933 934 final String action = intent.getAction(); 935 if (ACTION_PACKAGE_ADDED.equals(action) || ACTION_PACKAGE_REMOVED.equals(action)) { 936 final String packageName = intent.getData().getSchemeSpecificPart(); 937 if (intent.getBooleanExtra(EXTRA_REPLACING, false)) { 938 // Package removal/add is part of an update, so no need to modify package state. 939 return; 940 } 941 942 if (ACTION_PACKAGE_ADDED.equals(action)) { 943 onPackageAdded(packageName, userId); 944 } else if (ACTION_PACKAGE_REMOVED.equals(action)) { 945 onPackageRemoved(packageName, userId); 946 if (intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false)) { 947 onPackageRemovedForAllUsers(packageName); 948 } 949 } 950 } 951 } 952 }; 953 954 private final UsageEventListener mUsageEventListener = (userId, event) -> { 955 if (!isAppHibernationEnabled()) { 956 return; 957 } 958 final int eventType = event.mEventType; 959 if (eventType == UsageEvents.Event.USER_INTERACTION 960 || eventType == UsageEvents.Event.ACTIVITY_RESUMED 961 || eventType == UsageEvents.Event.APP_COMPONENT_USED) { 962 final String pkgName = event.mPackage; 963 setHibernatingForUser(pkgName, userId, false); 964 setHibernatingGlobally(pkgName, false); 965 } 966 }; 967 968 /** 969 * Whether app hibernation is enabled on this device. 970 * 971 * @return true if enabled, false otherwise 972 */ isAppHibernationEnabled()973 public static boolean isAppHibernationEnabled() { 974 return sIsServiceEnabled; 975 } 976 isDeviceConfigAppHibernationEnabled()977 private static boolean isDeviceConfigAppHibernationEnabled() { 978 return DeviceConfig.getBoolean( 979 NAMESPACE_APP_HIBERNATION, 980 KEY_APP_HIBERNATION_ENABLED, 981 true /* defaultValue */); 982 } 983 984 /** 985 * Dependency injector for {@link #AppHibernationService)}. 986 */ 987 interface Injector { getContext()988 Context getContext(); 989 getPackageManager()990 IPackageManager getPackageManager(); 991 getPackageManagerInternal()992 PackageManagerInternal getPackageManagerInternal(); 993 getActivityManager()994 IActivityManager getActivityManager(); 995 getUserManager()996 UserManager getUserManager(); 997 getStorageStatsManager()998 StorageStatsManager getStorageStatsManager(); 999 getBackgroundExecutor()1000 Executor getBackgroundExecutor(); 1001 getUsageStatsManagerInternal()1002 UsageStatsManagerInternal getUsageStatsManagerInternal(); 1003 getGlobalLevelDiskStore()1004 HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore(); 1005 getUserLevelDiskStore(int userId)1006 HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId); 1007 isOatArtifactDeletionEnabled()1008 boolean isOatArtifactDeletionEnabled(); 1009 } 1010 1011 private static final class InjectorImpl implements Injector { 1012 private static final String HIBERNATION_DIR_NAME = "hibernation"; 1013 private final Context mContext; 1014 private final ScheduledExecutorService mScheduledExecutorService; 1015 private final UserLevelHibernationProto mUserLevelHibernationProto; 1016 InjectorImpl(Context context)1017 InjectorImpl(Context context) { 1018 mContext = context; 1019 mScheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); 1020 mUserLevelHibernationProto = new UserLevelHibernationProto(); 1021 } 1022 1023 @Override getContext()1024 public Context getContext() { 1025 return mContext; 1026 } 1027 1028 @Override getPackageManager()1029 public IPackageManager getPackageManager() { 1030 return IPackageManager.Stub.asInterface(ServiceManager.getService("package")); 1031 } 1032 1033 @Override getPackageManagerInternal()1034 public PackageManagerInternal getPackageManagerInternal() { 1035 return LocalServices.getService(PackageManagerInternal.class); 1036 } 1037 1038 @Override getActivityManager()1039 public IActivityManager getActivityManager() { 1040 return ActivityManager.getService(); 1041 } 1042 1043 @Override getUserManager()1044 public UserManager getUserManager() { 1045 return mContext.getSystemService(UserManager.class); 1046 } 1047 1048 @Override getStorageStatsManager()1049 public StorageStatsManager getStorageStatsManager() { 1050 return mContext.getSystemService(StorageStatsManager.class); 1051 } 1052 1053 @Override getBackgroundExecutor()1054 public Executor getBackgroundExecutor() { 1055 return mScheduledExecutorService; 1056 } 1057 1058 @Override getUsageStatsManagerInternal()1059 public UsageStatsManagerInternal getUsageStatsManagerInternal() { 1060 return LocalServices.getService(UsageStatsManagerInternal.class); 1061 } 1062 1063 @Override getGlobalLevelDiskStore()1064 public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() { 1065 File dir = new File(Environment.getDataSystemDirectory(), HIBERNATION_DIR_NAME); 1066 return new HibernationStateDiskStore<>( 1067 dir, new GlobalLevelHibernationProto(), mScheduledExecutorService); 1068 } 1069 1070 @Override getUserLevelDiskStore(int userId)1071 public HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId) { 1072 File dir = new File(Environment.getDataSystemCeDirectory(userId), HIBERNATION_DIR_NAME); 1073 return new HibernationStateDiskStore<>( 1074 dir, mUserLevelHibernationProto, mScheduledExecutorService); 1075 } 1076 1077 @Override isOatArtifactDeletionEnabled()1078 public boolean isOatArtifactDeletionEnabled() { 1079 return mContext.getResources().getBoolean( 1080 com.android.internal.R.bool.config_hibernationDeletesOatArtifactsEnabled); 1081 } 1082 } 1083 1084 private final class StatsPullAtomCallbackImpl implements StatsPullAtomCallback { 1085 1086 private static final int MEGABYTE_IN_BYTES = 1000000; 1087 1088 @Override onPullAtom(int atomTag, @NonNull List<StatsEvent> data)1089 public int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) { 1090 if (!isAppHibernationEnabled() 1091 && (atomTag == FrameworkStatsLog.USER_LEVEL_HIBERNATED_APPS 1092 || atomTag == FrameworkStatsLog.GLOBAL_HIBERNATED_APPS)) { 1093 return StatsManager.PULL_SUCCESS; 1094 } 1095 1096 switch (atomTag) { 1097 case FrameworkStatsLog.USER_LEVEL_HIBERNATED_APPS: 1098 List<UserInfo> userInfos = mUserManager.getAliveUsers(); 1099 final int numUsers = userInfos.size(); 1100 for (int i = 0; i < numUsers; ++i) { 1101 final int userId = userInfos.get(i).id; 1102 if (mUserManager.isUserUnlockingOrUnlocked(userId)) { 1103 data.add( 1104 FrameworkStatsLog.buildStatsEvent( 1105 atomTag, 1106 getHibernatingPackagesForUser(userId).size(), 1107 userId) 1108 ); 1109 } 1110 } 1111 break; 1112 case FrameworkStatsLog.GLOBAL_HIBERNATED_APPS: 1113 int hibernatedAppCount = 0; 1114 long storage_saved_byte = 0; 1115 synchronized (mLock) { 1116 for (GlobalLevelState state : mGlobalHibernationStates.values()) { 1117 if (state.hibernated) { 1118 hibernatedAppCount++; 1119 storage_saved_byte += state.savedByte; 1120 } 1121 } 1122 } 1123 data.add( 1124 FrameworkStatsLog.buildStatsEvent( 1125 atomTag, 1126 hibernatedAppCount, 1127 storage_saved_byte / MEGABYTE_IN_BYTES) 1128 ); 1129 break; 1130 default: 1131 return StatsManager.PULL_SKIP; 1132 } 1133 return StatsManager.PULL_SUCCESS; 1134 } 1135 } 1136 } 1137