Merge "Exempt hibernating apps from dex optimization" into sc-v2-dev am: 9a8937e935
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16278552 Change-Id: I92cb6ed335caa67489e08617b5ba46efbdf4eb2e
This commit is contained in:
@@ -43,4 +43,9 @@ public abstract class AppHibernationManagerInternal {
|
|||||||
* @see AppHibernationService#setHibernatingGlobally
|
* @see AppHibernationService#setHibernatingGlobally
|
||||||
*/
|
*/
|
||||||
public abstract void setHibernatingGlobally(String packageName, boolean isHibernating);
|
public abstract void setHibernatingGlobally(String packageName, boolean isHibernating);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see AppHibernationService#isOatArtifactDeletionEnabled
|
||||||
|
*/
|
||||||
|
public abstract boolean isOatArtifactDeletionEnabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,6 +199,14 @@ public final class AppHibernationService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether global hibernation should delete ART ahead-of-time compilation artifacts and prevent
|
||||||
|
* package manager from re-optimizing the APK.
|
||||||
|
*/
|
||||||
|
private boolean isOatArtifactDeletionEnabled() {
|
||||||
|
return mOatArtifactDeletionEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether a package is hibernating for a given user.
|
* Whether a package is hibernating for a given user.
|
||||||
*
|
*
|
||||||
@@ -742,6 +750,11 @@ public final class AppHibernationService extends SystemService {
|
|||||||
public boolean isHibernatingGlobally(String packageName) {
|
public boolean isHibernatingGlobally(String packageName) {
|
||||||
return mService.isHibernatingGlobally(packageName);
|
return mService.isHibernatingGlobally(packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOatArtifactDeletionEnabled() {
|
||||||
|
return mService.isOatArtifactDeletionEnabled();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this);
|
private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this);
|
||||||
|
|||||||
@@ -381,7 +381,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Does the package have code? If not, there won't be any artifacts.
|
// Does the package have code? If not, there won't be any artifacts.
|
||||||
if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
|
if (!mPackageManagerService.mPackageDexOptimizer.canOptimizePackage(pkg)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pkg.getPath() == null) {
|
if (pkg.getPath() == null) {
|
||||||
|
|||||||
@@ -63,7 +63,10 @@ import android.util.Slog;
|
|||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
import com.android.server.LocalServices;
|
||||||
|
import com.android.server.apphibernation.AppHibernationManagerInternal;
|
||||||
import com.android.server.pm.Installer.InstallerException;
|
import com.android.server.pm.Installer.InstallerException;
|
||||||
import com.android.server.pm.dex.ArtManagerService;
|
import com.android.server.pm.dex.ArtManagerService;
|
||||||
import com.android.server.pm.dex.ArtStatsLogUtils;
|
import com.android.server.pm.dex.ArtStatsLogUtils;
|
||||||
@@ -107,16 +110,24 @@ public class PackageDexOptimizer {
|
|||||||
private volatile boolean mSystemReady;
|
private volatile boolean mSystemReady;
|
||||||
|
|
||||||
private final ArtStatsLogger mArtStatsLogger = new ArtStatsLogger();
|
private final ArtStatsLogger mArtStatsLogger = new ArtStatsLogger();
|
||||||
|
private final Injector mInjector;
|
||||||
|
|
||||||
|
|
||||||
private static final Random sRandom = new Random();
|
private static final Random sRandom = new Random();
|
||||||
|
|
||||||
PackageDexOptimizer(Installer installer, Object installLock, Context context,
|
PackageDexOptimizer(Installer installer, Object installLock, Context context,
|
||||||
String wakeLockTag) {
|
String wakeLockTag) {
|
||||||
this.mInstaller = installer;
|
this(new Injector() {
|
||||||
this.mInstallLock = installLock;
|
@Override
|
||||||
|
public AppHibernationManagerInternal getAppHibernationManagerInternal() {
|
||||||
|
return LocalServices.getService(AppHibernationManagerInternal.class);
|
||||||
|
}
|
||||||
|
|
||||||
PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
|
@Override
|
||||||
mDexoptWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLockTag);
|
public PowerManager getPowerManager(Context context) {
|
||||||
|
return context.getSystemService(PowerManager.class);
|
||||||
|
}
|
||||||
|
}, installer, installLock, context, wakeLockTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PackageDexOptimizer(PackageDexOptimizer from) {
|
protected PackageDexOptimizer(PackageDexOptimizer from) {
|
||||||
@@ -124,9 +135,21 @@ public class PackageDexOptimizer {
|
|||||||
this.mInstallLock = from.mInstallLock;
|
this.mInstallLock = from.mInstallLock;
|
||||||
this.mDexoptWakeLock = from.mDexoptWakeLock;
|
this.mDexoptWakeLock = from.mDexoptWakeLock;
|
||||||
this.mSystemReady = from.mSystemReady;
|
this.mSystemReady = from.mSystemReady;
|
||||||
|
this.mInjector = from.mInjector;
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean canOptimizePackage(AndroidPackage pkg) {
|
@VisibleForTesting
|
||||||
|
PackageDexOptimizer(@NonNull Injector injector, Installer installer, Object installLock,
|
||||||
|
Context context, String wakeLockTag) {
|
||||||
|
this.mInstaller = installer;
|
||||||
|
this.mInstallLock = installLock;
|
||||||
|
|
||||||
|
PowerManager powerManager = injector.getPowerManager(context);
|
||||||
|
mDexoptWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLockTag);
|
||||||
|
mInjector = injector;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canOptimizePackage(AndroidPackage pkg) {
|
||||||
// We do not dexopt a package with no code.
|
// We do not dexopt a package with no code.
|
||||||
// Note that the system package is marked as having no code, however we can
|
// Note that the system package is marked as having no code, however we can
|
||||||
// still optimize it via dexoptSystemServerPath.
|
// still optimize it via dexoptSystemServerPath.
|
||||||
@@ -134,6 +157,17 @@ public class PackageDexOptimizer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We do not dexopt unused packages.
|
||||||
|
// It's possible for this to be called before app hibernation service is ready due to
|
||||||
|
// an OTA dexopt. In this case, we ignore the hibernation check here. This is fine since
|
||||||
|
// a hibernating app should have no artifacts to copy in the first place.
|
||||||
|
AppHibernationManagerInternal ahm = mInjector.getAppHibernationManagerInternal();
|
||||||
|
if (ahm != null
|
||||||
|
&& ahm.isHibernatingGlobally(pkg.getPackageName())
|
||||||
|
&& ahm.isOatArtifactDeletionEnabled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -921,4 +955,13 @@ public class PackageDexOptimizer {
|
|||||||
return flags | DEXOPT_FORCE;
|
return flags | DEXOPT_FORCE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injector for {@link PackageDexOptimizer} dependencies
|
||||||
|
*/
|
||||||
|
interface Injector {
|
||||||
|
AppHibernationManagerInternal getAppHibernationManagerInternal();
|
||||||
|
|
||||||
|
PowerManager getPowerManager(Context context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -369,7 +369,6 @@ import com.android.server.SystemConfig;
|
|||||||
import com.android.server.SystemServerInitThreadPool;
|
import com.android.server.SystemServerInitThreadPool;
|
||||||
import com.android.server.Watchdog;
|
import com.android.server.Watchdog;
|
||||||
import com.android.server.apphibernation.AppHibernationManagerInternal;
|
import com.android.server.apphibernation.AppHibernationManagerInternal;
|
||||||
import com.android.server.apphibernation.AppHibernationService;
|
|
||||||
import com.android.server.compat.CompatChange;
|
import com.android.server.compat.CompatChange;
|
||||||
import com.android.server.compat.PlatformCompat;
|
import com.android.server.compat.PlatformCompat;
|
||||||
import com.android.server.net.NetworkPolicyManagerInternal;
|
import com.android.server.net.NetworkPolicyManagerInternal;
|
||||||
@@ -1460,7 +1459,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
|
|
||||||
final ArtManagerService mArtManagerService;
|
final ArtManagerService mArtManagerService;
|
||||||
|
|
||||||
private final PackageDexOptimizer mPackageDexOptimizer;
|
final PackageDexOptimizer mPackageDexOptimizer;
|
||||||
// DexManager handles the usage of dex files (e.g. secondary files, whether or not a package
|
// DexManager handles the usage of dex files (e.g. secondary files, whether or not a package
|
||||||
// is used by other apps).
|
// is used by other apps).
|
||||||
private final DexManager mDexManager;
|
private final DexManager mDexManager;
|
||||||
@@ -12750,7 +12749,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
|
if (!mPackageDexOptimizer.canOptimizePackage(pkg)) {
|
||||||
if (DEBUG_DEXOPT) {
|
if (DEBUG_DEXOPT) {
|
||||||
Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName());
|
Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName());
|
||||||
}
|
}
|
||||||
@@ -13001,16 +13000,11 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
ArraySet<String> pkgs = new ArraySet<>();
|
ArraySet<String> pkgs = new ArraySet<>();
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
for (AndroidPackage p : mPackages.values()) {
|
for (AndroidPackage p : mPackages.values()) {
|
||||||
if (PackageDexOptimizer.canOptimizePackage(p)) {
|
if (mPackageDexOptimizer.canOptimizePackage(p)) {
|
||||||
pkgs.add(p.getPackageName());
|
pkgs.add(p.getPackageName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (AppHibernationService.isAppHibernationEnabled()) {
|
|
||||||
AppHibernationManagerInternal appHibernationManager =
|
|
||||||
mInjector.getLocalService(AppHibernationManagerInternal.class);
|
|
||||||
pkgs.removeIf(pkgName -> appHibernationManager.isHibernatingGlobally(pkgName));
|
|
||||||
}
|
|
||||||
return pkgs;
|
return pkgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
package com.android.server.pm
|
package com.android.server.pm
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
import android.os.PowerManager
|
||||||
import android.provider.DeviceConfig
|
import android.provider.DeviceConfig
|
||||||
import android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION
|
import android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION
|
||||||
import android.testing.AndroidTestingRunner
|
import android.testing.AndroidTestingRunner
|
||||||
@@ -55,6 +57,8 @@ class PackageManagerServiceHibernationTests {
|
|||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var appHibernationManager: AppHibernationManagerInternal
|
lateinit var appHibernationManager: AppHibernationManagerInternal
|
||||||
|
@Mock
|
||||||
|
lateinit var powerManager: PowerManager
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
@@ -68,6 +72,24 @@ class PackageManagerServiceHibernationTests {
|
|||||||
.thenReturn(appHibernationManager)
|
.thenReturn(appHibernationManager)
|
||||||
whenever(rule.mocks().injector.handler)
|
whenever(rule.mocks().injector.handler)
|
||||||
.thenReturn(Handler(TestableLooper.get(this).looper))
|
.thenReturn(Handler(TestableLooper.get(this).looper))
|
||||||
|
val injector = object : PackageDexOptimizer.Injector {
|
||||||
|
override fun getAppHibernationManagerInternal(): AppHibernationManagerInternal {
|
||||||
|
return appHibernationManager
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPowerManager(context: Context?): PowerManager {
|
||||||
|
return powerManager
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val packageDexOptimizer = PackageDexOptimizer(
|
||||||
|
injector,
|
||||||
|
rule.mocks().installer,
|
||||||
|
rule.mocks().installLock,
|
||||||
|
rule.mocks().context,
|
||||||
|
"*dexopt*")
|
||||||
|
whenever(rule.mocks().injector.packageDexOptimizer)
|
||||||
|
.thenReturn(packageDexOptimizer)
|
||||||
|
whenever(appHibernationManager.isOatArtifactDeletionEnabled).thenReturn(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user