Loading services/core/java/android/content/pm/PackageManagerInternal.java +5 −0 Original line number Diff line number Diff line Loading @@ -1141,4 +1141,9 @@ public abstract class PackageManagerInternal { */ public abstract boolean isPackageFrozen( @NonNull String packageName, int callingUid, int userId); /** * Deletes the OAT artifacts of a package. */ public abstract void deleteOatArtifactsOfPackage(String packageName); } services/core/java/com/android/server/apphibernation/AppHibernationService.java +15 −3 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.Environment; import android.os.RemoteException; Loading Loading @@ -92,8 +93,10 @@ public final class AppHibernationService extends SystemService { private final Object mLock = new Object(); private final Context mContext; private final IPackageManager mIPackageManager; private final PackageManagerInternal mPackageManagerInternal; private final IActivityManager mIActivityManager; private final UserManager mUserManager; @GuardedBy("mLock") private final SparseArray<Map<String, UserLevelState>> mUserStates = new SparseArray<>(); private final SparseArray<HibernationStateDiskStore<UserLevelState>> mUserDiskStores = Loading Loading @@ -125,6 +128,7 @@ public final class AppHibernationService extends SystemService { super(injector.getContext()); mContext = injector.getContext(); mIPackageManager = injector.getPackageManager(); mPackageManagerInternal = injector.getPackageManagerInternal(); mIActivityManager = injector.getActivityManager(); mUserManager = injector.getUserManager(); mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore(); Loading Loading @@ -214,8 +218,9 @@ public final class AppHibernationService extends SystemService { synchronized (mLock) { GlobalLevelState state = mGlobalHibernationStates.get(packageName); if (state == null) { throw new IllegalArgumentException( String.format("Package %s is not installed", packageName)); // This API can be legitimately called before installation finishes as part of // dex optimization, so we just return false here. return false; } return state.hibernated; } Loading Loading @@ -366,7 +371,7 @@ public final class AppHibernationService extends SystemService { @GuardedBy("mLock") private void hibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) { Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally"); // TODO(175830194): Delete vdex/odex when DexManager API is built out mPackageManagerInternal.deleteOatArtifactsOfPackage(packageName); state.hibernated = true; Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } Loading Loading @@ -728,6 +733,8 @@ public final class AppHibernationService extends SystemService { IPackageManager getPackageManager(); PackageManagerInternal getPackageManagerInternal(); IActivityManager getActivityManager(); UserManager getUserManager(); Loading Loading @@ -761,6 +768,11 @@ public final class AppHibernationService extends SystemService { return IPackageManager.Stub.asInterface(ServiceManager.getService("package")); } @Override public PackageManagerInternal getPackageManagerInternal() { return LocalServices.getService(PackageManagerInternal.class); } @Override public IActivityManager getActivityManager() { return ActivityManager.getService(); Loading services/core/java/com/android/server/pm/PackageManagerService.java +13 −2 Original line number Diff line number Diff line Loading @@ -252,7 +252,6 @@ import android.content.pm.parsing.component.ParsedPermissionGroup; import android.content.pm.parsing.component.ParsedProcess; import android.content.pm.parsing.component.ParsedProvider; import android.content.pm.parsing.component.ParsedService; import android.content.pm.parsing.component.ParsedUsesPermission; import android.content.pm.parsing.result.ParseResult; import android.content.pm.parsing.result.ParseTypeImpl; import android.content.res.Resources; Loading Loading @@ -371,6 +370,7 @@ import com.android.server.SystemConfig; import com.android.server.SystemServerInitThreadPool; import com.android.server.Watchdog; import com.android.server.apphibernation.AppHibernationManagerInternal; import com.android.server.apphibernation.AppHibernationService; import com.android.server.compat.CompatChange; import com.android.server.compat.PlatformCompat; import com.android.server.net.NetworkPolicyManagerInternal; Loading Loading @@ -12304,9 +12304,15 @@ public class PackageManagerService extends IPackageManager.Stub public ArraySet<String> getOptimizablePackages() { ArraySet<String> pkgs = new ArraySet<>(); final boolean hibernationEnabled = AppHibernationService.isAppHibernationEnabled(); AppHibernationManagerInternal appHibernationManager = mInjector.getLocalService(AppHibernationManagerInternal.class); synchronized (mLock) { for (AndroidPackage p : mPackages.values()) { if (PackageDexOptimizer.canOptimizePackage(p)) { // Checking hibernation state is an inexpensive call. boolean isHibernating = hibernationEnabled && appHibernationManager.isHibernatingGlobally(p.getPackageName()); if (PackageDexOptimizer.canOptimizePackage(p) && !isHibernating) { pkgs.add(p.getPackageName()); } } Loading Loading @@ -27329,6 +27335,11 @@ public class PackageManagerService extends IPackageManager.Stub return PackageManagerService.this.getPackageStartability( packageName, callingUid, userId) == PACKAGE_STARTABILITY_FROZEN; } @Override public void deleteOatArtifactsOfPackage(String packageName) { PackageManagerService.this.deleteOatArtifactsOfPackage(packageName); } } @GuardedBy("mLock") services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +2 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.os.SystemProperties import android.os.UserHandle import android.os.UserManager import android.os.incremental.IncrementalManager import android.provider.DeviceConfig import android.util.ArrayMap import android.util.DisplayMetrics import android.util.EventLog Loading Loading @@ -131,6 +132,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { .mockStatic(LockGuard::class.java) .mockStatic(EventLog::class.java) .mockStatic(LocalServices::class.java) .mockStatic(DeviceConfig::class.java) .apply(withSession) session = apply.startMocking() whenever(mocks.settings.insertPackageSettingLPw( Loading services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt +32 −0 Original line number Diff line number Diff line Loading @@ -17,8 +17,13 @@ package com.android.server.pm import android.os.Build import android.provider.DeviceConfig import android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION import com.android.server.apphibernation.AppHibernationManagerInternal import com.android.server.extendedtestutils.wheneverStatic import com.android.server.testutils.whenever import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test Loading @@ -33,7 +38,10 @@ class PackageManagerServiceHibernationTests { companion object { val TEST_PACKAGE_NAME = "test.package" val TEST_PACKAGE_2_NAME = "test.package2" val TEST_USER_ID = 0 val KEY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled" } @Rule Loading @@ -47,6 +55,8 @@ class PackageManagerServiceHibernationTests { @Throws(Exception::class) fun setup() { MockitoAnnotations.initMocks(this) wheneverStatic { DeviceConfig.getBoolean( NAMESPACE_APP_HIBERNATION, KEY_APP_HIBERNATION_ENABLED, false) }.thenReturn(true) rule.system().stageNominalSystemState() whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java)) .thenReturn(appHibernationManager) Loading @@ -68,6 +78,28 @@ class PackageManagerServiceHibernationTests { verify(appHibernationManager).setHibernatingGlobally(TEST_PACKAGE_NAME, false) } @Test fun testGetOptimizablePackages_ExcludesGloballyHibernatingPackages() { rule.system().stageScanExistingPackage( TEST_PACKAGE_NAME, 1L, rule.system().dataAppDirectory, withPackage = { it.apply { isHasCode = true } }) rule.system().stageScanExistingPackage( TEST_PACKAGE_2_NAME, 1L, rule.system().dataAppDirectory, withPackage = { it.apply { isHasCode = true } }) val pm = createPackageManagerService() rule.system().validateFinalState() whenever(appHibernationManager.isHibernatingGlobally(TEST_PACKAGE_2_NAME)).thenReturn(true) val optimizablePkgs = pm.optimizablePackages assertTrue(optimizablePkgs.contains(TEST_PACKAGE_NAME)) assertFalse(optimizablePkgs.contains(TEST_PACKAGE_2_NAME)) } private fun createPackageManagerService(): PackageManagerService { return PackageManagerService(rule.mocks().injector, false /*coreOnly*/, Loading Loading
services/core/java/android/content/pm/PackageManagerInternal.java +5 −0 Original line number Diff line number Diff line Loading @@ -1141,4 +1141,9 @@ public abstract class PackageManagerInternal { */ public abstract boolean isPackageFrozen( @NonNull String packageName, int callingUid, int userId); /** * Deletes the OAT artifacts of a package. */ public abstract void deleteOatArtifactsOfPackage(String packageName); }
services/core/java/com/android/server/apphibernation/AppHibernationService.java +15 −3 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.Environment; import android.os.RemoteException; Loading Loading @@ -92,8 +93,10 @@ public final class AppHibernationService extends SystemService { private final Object mLock = new Object(); private final Context mContext; private final IPackageManager mIPackageManager; private final PackageManagerInternal mPackageManagerInternal; private final IActivityManager mIActivityManager; private final UserManager mUserManager; @GuardedBy("mLock") private final SparseArray<Map<String, UserLevelState>> mUserStates = new SparseArray<>(); private final SparseArray<HibernationStateDiskStore<UserLevelState>> mUserDiskStores = Loading Loading @@ -125,6 +128,7 @@ public final class AppHibernationService extends SystemService { super(injector.getContext()); mContext = injector.getContext(); mIPackageManager = injector.getPackageManager(); mPackageManagerInternal = injector.getPackageManagerInternal(); mIActivityManager = injector.getActivityManager(); mUserManager = injector.getUserManager(); mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore(); Loading Loading @@ -214,8 +218,9 @@ public final class AppHibernationService extends SystemService { synchronized (mLock) { GlobalLevelState state = mGlobalHibernationStates.get(packageName); if (state == null) { throw new IllegalArgumentException( String.format("Package %s is not installed", packageName)); // This API can be legitimately called before installation finishes as part of // dex optimization, so we just return false here. return false; } return state.hibernated; } Loading Loading @@ -366,7 +371,7 @@ public final class AppHibernationService extends SystemService { @GuardedBy("mLock") private void hibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) { Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally"); // TODO(175830194): Delete vdex/odex when DexManager API is built out mPackageManagerInternal.deleteOatArtifactsOfPackage(packageName); state.hibernated = true; Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } Loading Loading @@ -728,6 +733,8 @@ public final class AppHibernationService extends SystemService { IPackageManager getPackageManager(); PackageManagerInternal getPackageManagerInternal(); IActivityManager getActivityManager(); UserManager getUserManager(); Loading Loading @@ -761,6 +768,11 @@ public final class AppHibernationService extends SystemService { return IPackageManager.Stub.asInterface(ServiceManager.getService("package")); } @Override public PackageManagerInternal getPackageManagerInternal() { return LocalServices.getService(PackageManagerInternal.class); } @Override public IActivityManager getActivityManager() { return ActivityManager.getService(); Loading
services/core/java/com/android/server/pm/PackageManagerService.java +13 −2 Original line number Diff line number Diff line Loading @@ -252,7 +252,6 @@ import android.content.pm.parsing.component.ParsedPermissionGroup; import android.content.pm.parsing.component.ParsedProcess; import android.content.pm.parsing.component.ParsedProvider; import android.content.pm.parsing.component.ParsedService; import android.content.pm.parsing.component.ParsedUsesPermission; import android.content.pm.parsing.result.ParseResult; import android.content.pm.parsing.result.ParseTypeImpl; import android.content.res.Resources; Loading Loading @@ -371,6 +370,7 @@ import com.android.server.SystemConfig; import com.android.server.SystemServerInitThreadPool; import com.android.server.Watchdog; import com.android.server.apphibernation.AppHibernationManagerInternal; import com.android.server.apphibernation.AppHibernationService; import com.android.server.compat.CompatChange; import com.android.server.compat.PlatformCompat; import com.android.server.net.NetworkPolicyManagerInternal; Loading Loading @@ -12304,9 +12304,15 @@ public class PackageManagerService extends IPackageManager.Stub public ArraySet<String> getOptimizablePackages() { ArraySet<String> pkgs = new ArraySet<>(); final boolean hibernationEnabled = AppHibernationService.isAppHibernationEnabled(); AppHibernationManagerInternal appHibernationManager = mInjector.getLocalService(AppHibernationManagerInternal.class); synchronized (mLock) { for (AndroidPackage p : mPackages.values()) { if (PackageDexOptimizer.canOptimizePackage(p)) { // Checking hibernation state is an inexpensive call. boolean isHibernating = hibernationEnabled && appHibernationManager.isHibernatingGlobally(p.getPackageName()); if (PackageDexOptimizer.canOptimizePackage(p) && !isHibernating) { pkgs.add(p.getPackageName()); } } Loading Loading @@ -27329,6 +27335,11 @@ public class PackageManagerService extends IPackageManager.Stub return PackageManagerService.this.getPackageStartability( packageName, callingUid, userId) == PACKAGE_STARTABILITY_FROZEN; } @Override public void deleteOatArtifactsOfPackage(String packageName) { PackageManagerService.this.deleteOatArtifactsOfPackage(packageName); } } @GuardedBy("mLock")
services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +2 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.os.SystemProperties import android.os.UserHandle import android.os.UserManager import android.os.incremental.IncrementalManager import android.provider.DeviceConfig import android.util.ArrayMap import android.util.DisplayMetrics import android.util.EventLog Loading Loading @@ -131,6 +132,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { .mockStatic(LockGuard::class.java) .mockStatic(EventLog::class.java) .mockStatic(LocalServices::class.java) .mockStatic(DeviceConfig::class.java) .apply(withSession) session = apply.startMocking() whenever(mocks.settings.insertPackageSettingLPw( Loading
services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt +32 −0 Original line number Diff line number Diff line Loading @@ -17,8 +17,13 @@ package com.android.server.pm import android.os.Build import android.provider.DeviceConfig import android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION import com.android.server.apphibernation.AppHibernationManagerInternal import com.android.server.extendedtestutils.wheneverStatic import com.android.server.testutils.whenever import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test Loading @@ -33,7 +38,10 @@ class PackageManagerServiceHibernationTests { companion object { val TEST_PACKAGE_NAME = "test.package" val TEST_PACKAGE_2_NAME = "test.package2" val TEST_USER_ID = 0 val KEY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled" } @Rule Loading @@ -47,6 +55,8 @@ class PackageManagerServiceHibernationTests { @Throws(Exception::class) fun setup() { MockitoAnnotations.initMocks(this) wheneverStatic { DeviceConfig.getBoolean( NAMESPACE_APP_HIBERNATION, KEY_APP_HIBERNATION_ENABLED, false) }.thenReturn(true) rule.system().stageNominalSystemState() whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java)) .thenReturn(appHibernationManager) Loading @@ -68,6 +78,28 @@ class PackageManagerServiceHibernationTests { verify(appHibernationManager).setHibernatingGlobally(TEST_PACKAGE_NAME, false) } @Test fun testGetOptimizablePackages_ExcludesGloballyHibernatingPackages() { rule.system().stageScanExistingPackage( TEST_PACKAGE_NAME, 1L, rule.system().dataAppDirectory, withPackage = { it.apply { isHasCode = true } }) rule.system().stageScanExistingPackage( TEST_PACKAGE_2_NAME, 1L, rule.system().dataAppDirectory, withPackage = { it.apply { isHasCode = true } }) val pm = createPackageManagerService() rule.system().validateFinalState() whenever(appHibernationManager.isHibernatingGlobally(TEST_PACKAGE_2_NAME)).thenReturn(true) val optimizablePkgs = pm.optimizablePackages assertTrue(optimizablePkgs.contains(TEST_PACKAGE_NAME)) assertFalse(optimizablePkgs.contains(TEST_PACKAGE_2_NAME)) } private fun createPackageManagerService(): PackageManagerService { return PackageManagerService(rule.mocks().injector, false /*coreOnly*/, Loading