Allow AppHibernationManager to be null for boot time compilations.
This is necessary due to initialization order in the system server.
Test: Boot with dalvik.vm.useartservice=true
Bug: 251903639
Ignore-AOSP-First: ART Services.
Change-Id: I0358ccdf027de2169a6ab35eb24ec3300f210c08
diff --git a/libartservice/service/java/com/android/server/art/ArtManagerLocal.java b/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
index 864a26d..a316fe5 100644
--- a/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
+++ b/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
@@ -148,7 +148,7 @@
/**
* Deletes dexopt artifacts of a package, including the artifacts for primary dex files and the
- * ones for secondary dex files.
+ * ones for secondary dex files. This includes VDEX, ODEX, and ART files.
*
* @throws IllegalArgumentException if the package is not found or the flags are illegal
* @throws IllegalStateException if the operation encounters an error that should never happen
@@ -820,10 +820,28 @@
@NonNull
private List<String> getDefaultPackages(
@NonNull PackageManagerLocal.FilteredSnapshot snapshot, @NonNull String reason) {
+ // We probably won't have an app hibernation manager in the boot time compilation, because
+ // ArtManagerLocal.onBoot needs to run early to ensure apps are compiled before the system
+ // server fires them up. This means the boot time compilation will ignore the hibernation
+ // states of the packages.
+ //
+ // TODO(b/265782156): When hibernated packages get compiled this way, the file GC will
+ // delete them again in the next background dexopt run. That means they are likely to get
+ // recreated again in the next boot dexopt (i.e. for OTA or Mainline update).
+ var appHibernationManager = mInjector.getAppHibernationManager();
+ if (reason != ReasonMapping.REASON_FIRST_BOOT
+ && reason != ReasonMapping.REASON_BOOT_AFTER_OTA
+ && reason != ReasonMapping.REASON_BOOT_AFTER_MAINLINE_UPDATE) {
+ // Check that it's present for other compilation reasons, to ensure we don't regress
+ // silently.
+ Objects.requireNonNull(appHibernationManager);
+ }
+
// Filter out hibernating packages even if the reason is REASON_INACTIVE. This is because
// artifacts for hibernating packages are already deleted.
Stream<PackageState> packages = snapshot.getPackageStates().values().stream().filter(
- pkgState -> Utils.canDexoptPackage(pkgState, mInjector.getAppHibernationManager()));
+ pkgState -> Utils.canDexoptPackage(pkgState, appHibernationManager));
+
switch (reason) {
case ReasonMapping.REASON_BOOT_AFTER_MAINLINE_UPDATE:
packages = packages.filter(
@@ -839,6 +857,7 @@
packages = filterAndSortByLastActiveTime(
packages, true /* keepRecent */, true /* descending */);
}
+
return packages.map(PackageState::getPackageName).collect(Collectors.toList());
}
@@ -989,10 +1008,9 @@
mConfig = new Config();
mBgDexoptJob = new BackgroundDexoptJob(context, artManagerLocal, mConfig);
- // Call the getters for various dependencies, to ensure correct initialization
- // order.
+ // Call the getters for the dependencies that aren't optional, to ensure correct
+ // initialization order.
getDexoptHelper();
- getAppHibernationManager();
getUserManager();
getDexUseManager();
getStorageManager();
@@ -1029,9 +1047,16 @@
return mConfig;
}
- @NonNull
+ /**
+ * Returns the registered AppHibernationManager instance.
+ *
+ * It may be null because ArtManagerLocal needs to be available early to compile packages at
+ * boot with {@link onBoot}, before the hibernation manager has been initialized. It should
+ * not be null for other dexopt calls.
+ */
+ @Nullable
public AppHibernationManager getAppHibernationManager() {
- return Objects.requireNonNull(mContext.getSystemService(AppHibernationManager.class));
+ return mContext.getSystemService(AppHibernationManager.class);
}
@NonNull
diff --git a/libartservice/service/java/com/android/server/art/DexoptHelper.java b/libartservice/service/java/com/android/server/art/DexoptHelper.java
index af0f20f..e178cc4 100644
--- a/libartservice/service/java/com/android/server/art/DexoptHelper.java
+++ b/libartservice/service/java/com/android/server/art/DexoptHelper.java
@@ -243,6 +243,9 @@
}
private boolean canDexoptPackage(@NonNull PackageState pkgState) {
+ // getAppHibernationManager may return null here during boot time compilation, which will
+ // make this function return true incorrectly for packages that shouldn't be dexopted due to
+ // hibernation. Further discussion in comments in ArtManagerLocal.getDefaultPackages.
return Utils.canDexoptPackage(pkgState, mInjector.getAppHibernationManager());
}
@@ -311,8 +314,8 @@
mContext = context;
mConfig = config;
- // Call the getters for various dependencies, to ensure correct initialization order.
- getAppHibernationManager();
+ // Call the getters for the dependencies that aren't optional, to ensure correct
+ // initialization order.
getPowerManager();
}
@@ -330,9 +333,16 @@
return new SecondaryDexopter(mContext, pkgState, pkg, params, cancellationSignal);
}
- @NonNull
+ /**
+ * Returns the registered AppHibernationManager instance.
+ *
+ * It may be null because ArtManagerLocal needs to be available early to compile packages at
+ * boot with {@link onBoot}, before the hibernation manager has been initialized. It should
+ * not be null for other dexopt calls.
+ */
+ @Nullable
public AppHibernationManager getAppHibernationManager() {
- return Objects.requireNonNull(mContext.getSystemService(AppHibernationManager.class));
+ return mContext.getSystemService(AppHibernationManager.class);
}
@NonNull