Disallow PowerManager and AppHibernationManager to be missing.
We can safely assume that PowerManager and AppHibernationManager always
exist because:
- PowerManager is available once PowerManagerService and
ThermalManagerService are initialized.
- AppHibernationManager is available once AppHibernationService is
initialized.
- PowerManagerService, ThermalManagerService, and AppHibernationService
are all initialized before ArtManagerLocal, and the initializations
are blocking.
Bug: 244289352
Test: manual - call `optimizePackage` in `ArtManagerLocal` constructor
and see the optimization successful.
Ignore-AOSP-First: ART Services
Change-Id: I0c307fac2772fec3d8a0383f99e6cfb78163cb61
diff --git a/libartservice/service/java/com/android/server/art/DexOptHelper.java b/libartservice/service/java/com/android/server/art/DexOptHelper.java
index e73abcb..6d9c85a 100644
--- a/libartservice/service/java/com/android/server/art/DexOptHelper.java
+++ b/libartservice/service/java/com/android/server/art/DexOptHelper.java
@@ -88,14 +88,10 @@
try {
// Acquire a wake lock.
- // The power manager service may not be ready if this method is called on boot. In this
- // case, we don't have to acquire a wake lock because there is nothing else we can do.
PowerManager powerManager = mInjector.getPowerManager();
- if (powerManager != null) {
- wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- wakeLock.setWorkSource(new WorkSource(pkg.getUid()));
- wakeLock.acquire(WAKE_LOCK_TIMEOUT_MS);
- }
+ wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ wakeLock.setWorkSource(new WorkSource(pkg.getUid()));
+ wakeLock.acquire(WAKE_LOCK_TIMEOUT_MS);
if ((params.getFlags() & ArtFlags.FLAG_FOR_PRIMARY_DEX) != 0) {
results.addAll(mInjector.getPrimaryDexOptimizer().dexopt(pkgState, pkg, params));
@@ -129,11 +125,8 @@
}
// We do not dexopt unused packages.
- // It's possible for this to be called before app hibernation service is ready, especially
- // on boot. In this case, we ignore the hibernation check here because there is nothing else
- // we can do.
AppHibernationManager ahm = mInjector.getAppHibernationManager();
- if (ahm != null && ahm.isHibernatingGlobally(pkgState.getPackageName())
+ if (ahm.isHibernatingGlobally(pkgState.getPackageName())
&& ahm.isOatArtifactDeletionEnabled()) {
return false;
}
@@ -159,14 +152,12 @@
return new PrimaryDexOptimizer(mContext);
}
- // TODO(b/244289352): Investigate whether this can be @NonNull.
- @Nullable
+ @NonNull
public AppHibernationManager getAppHibernationManager() {
return mContext.getSystemService(AppHibernationManager.class);
}
- // TODO(b/244289352): Investigate whether this can be @NonNull.
- @Nullable
+ @NonNull
public PowerManager getPowerManager() {
return mContext.getSystemService(PowerManager.class);
}
diff --git a/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java b/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
index 1b9c852..518b972 100644
--- a/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
+++ b/libartservice/service/javatests/com/android/server/art/DexOptHelperTest.java
@@ -62,6 +62,7 @@
@Mock private PrimaryDexOptimizer mPrimaryDexOptimizer;
@Mock private AppHibernationManager mAhm;
@Mock private PowerManager mPowerManager;
+ @Mock private PowerManager.WakeLock mWakeLock;
private PackageState mPkgState;
private AndroidPackageApi mPkg;
@@ -84,8 +85,15 @@
@Before
public void setUp() throws Exception {
lenient().when(mInjector.getPrimaryDexOptimizer()).thenReturn(mPrimaryDexOptimizer);
- lenient().when(mInjector.getAppHibernationManager()).thenReturn(null);
- lenient().when(mInjector.getPowerManager()).thenReturn(null);
+ lenient().when(mInjector.getAppHibernationManager()).thenReturn(mAhm);
+ lenient().when(mInjector.getPowerManager()).thenReturn(mPowerManager);
+
+ lenient()
+ .when(mPowerManager.newWakeLock(eq(PowerManager.PARTIAL_WAKE_LOCK), any()))
+ .thenReturn(mWakeLock);
+
+ lenient().when(mAhm.isHibernatingGlobally(PKG_NAME)).thenReturn(false);
+ lenient().when(mAhm.isOatArtifactDeletionEnabled()).thenReturn(true);
mPkgState = createPackageState();
mPkg = mPkgState.getAndroidPackage();
@@ -106,6 +114,11 @@
assertThat(result.getReason()).isEqualTo("install");
assertThat(result.getFinalStatus()).isEqualTo(OptimizeResult.OPTIMIZE_FAILED);
assertThat(result.getDexFileOptimizeResults()).containsExactlyElementsIn(mPrimaryResults);
+
+ InOrder inOrder = inOrder(mPrimaryDexOptimizer, mWakeLock);
+ inOrder.verify(mWakeLock).acquire(anyLong());
+ inOrder.verify(mPrimaryDexOptimizer).dexopt(any(), any(), any());
+ inOrder.verify(mWakeLock).release();
}
@Test
@@ -120,25 +133,8 @@
}
@Test
- public void testDexoptWithAppHibernationManager() throws Exception {
- when(mInjector.getAppHibernationManager()).thenReturn(mAhm);
- lenient().when(mAhm.isHibernatingGlobally(PKG_NAME)).thenReturn(false);
- lenient().when(mAhm.isOatArtifactDeletionEnabled()).thenReturn(true);
-
- when(mPrimaryDexOptimizer.dexopt(same(mPkgState), same(mPkg), same(mParams)))
- .thenReturn(mPrimaryResults);
-
- OptimizeResult result =
- mDexOptHelper.dexopt(mock(PackageDataSnapshot.class), mPkgState, mPkg, mParams);
-
- assertThat(result.getDexFileOptimizeResults()).containsExactlyElementsIn(mPrimaryResults);
- }
-
- @Test
public void testDexoptIsHibernating() throws Exception {
- when(mInjector.getAppHibernationManager()).thenReturn(mAhm);
lenient().when(mAhm.isHibernatingGlobally(PKG_NAME)).thenReturn(true);
- lenient().when(mAhm.isOatArtifactDeletionEnabled()).thenReturn(true);
OptimizeResult result =
mDexOptHelper.dexopt(mock(PackageDataSnapshot.class), mPkgState, mPkg, mParams);
@@ -149,7 +145,6 @@
@Test
public void testDexoptIsHibernatingButOatArtifactDeletionDisabled() throws Exception {
- when(mInjector.getAppHibernationManager()).thenReturn(mAhm);
lenient().when(mAhm.isHibernatingGlobally(PKG_NAME)).thenReturn(true);
lenient().when(mAhm.isOatArtifactDeletionEnabled()).thenReturn(false);
@@ -163,31 +158,7 @@
}
@Test
- public void testDexoptWithPowerManager() throws Exception {
- var wakeLock = mock(PowerManager.WakeLock.class);
- when(mInjector.getPowerManager()).thenReturn(mPowerManager);
- when(mPowerManager.newWakeLock(eq(PowerManager.PARTIAL_WAKE_LOCK), any()))
- .thenReturn(wakeLock);
-
- when(mPrimaryDexOptimizer.dexopt(same(mPkgState), same(mPkg), same(mParams)))
- .thenReturn(mPrimaryResults);
-
- OptimizeResult result =
- mDexOptHelper.dexopt(mock(PackageDataSnapshot.class), mPkgState, mPkg, mParams);
-
- InOrder inOrder = inOrder(mPrimaryDexOptimizer, wakeLock);
- inOrder.verify(wakeLock).acquire(anyLong());
- inOrder.verify(mPrimaryDexOptimizer).dexopt(any(), any(), any());
- inOrder.verify(wakeLock).release();
- }
-
- @Test
public void testDexoptAlwaysReleasesWakeLock() throws Exception {
- var wakeLock = mock(PowerManager.WakeLock.class);
- when(mInjector.getPowerManager()).thenReturn(mPowerManager);
- when(mPowerManager.newWakeLock(eq(PowerManager.PARTIAL_WAKE_LOCK), any()))
- .thenReturn(wakeLock);
-
when(mPrimaryDexOptimizer.dexopt(same(mPkgState), same(mPkg), same(mParams)))
.thenThrow(IllegalStateException.class);
@@ -197,7 +168,7 @@
} catch (Exception e) {
}
- verify(wakeLock).release();
+ verify(mWakeLock).release();
}
private AndroidPackageApi createPackage() {