summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java52
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java5
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java89
3 files changed, 136 insertions, 10 deletions
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index e7d0c41c0fea..65b7cf3eabd1 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -51,6 +51,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.os.storage.StorageManager;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -79,7 +80,7 @@ import java.util.Map;
* Helper class for running dexopt command on packages.
*/
public class PackageDexOptimizer {
- private static final String TAG = "PackageManager.DexOptimizer";
+ private static final String TAG = "PackageDexOptimizer";
static final String OAT_DIR_NAME = "oat";
// TODO b/19550105 Remove error codes and use exceptions
public static final int DEX_OPT_SKIPPED = 0;
@@ -307,6 +308,55 @@ public class PackageDexOptimizer {
}
}
+ /**
+ * Perform dexopt (if needed) on a system server code path).
+ */
+ public int dexoptSystemServerPath(
+ String dexPath, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
+ int dexoptFlags = DEXOPT_PUBLIC
+ | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0)
+ | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0);
+
+ int result = DEX_OPT_SKIPPED;
+ for (String isa : dexUseInfo.getLoaderIsas()) {
+ int dexoptNeeded = getDexoptNeeded(
+ dexPath,
+ isa,
+ options.getCompilerFilter(),
+ dexUseInfo.getClassLoaderContext(),
+ /* newProfile= */false,
+ /* downgrade= */ false);
+
+ if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
+ continue;
+ }
+ try {
+ mInstaller.dexopt(
+ dexPath,
+ android.os.Process.SYSTEM_UID,
+ /* packageName= */ "android",
+ isa,
+ dexoptNeeded,
+ /* oatDir= */ null,
+ dexoptFlags,
+ options.getCompilerFilter(),
+ StorageManager.UUID_PRIVATE_INTERNAL,
+ dexUseInfo.getClassLoaderContext(),
+ /* seInfo= */ null,
+ /* downgrade= */ false ,
+ /* targetSdk= */ 0,
+ /* profileName */ null,
+ /* dexMetadataPath */ null,
+ getReasonName(options.getCompilationReason()));
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to dexopt", e);
+ return DEX_OPT_FAILED;
+ }
+ result = DEX_OPT_PERFORMED;
+ }
+ return result;
+ }
+
private String getAugmentedReasonName(int compilationReason, boolean useDexMetadata) {
String annotation = useDexMetadata
? ArtManagerService.DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : "";
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f693555d9761..9c41e6d5c6a3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9855,6 +9855,11 @@ public class PackageManagerService extends IPackageManager.Stub
private int performDexOptInternalWithDependenciesLI(AndroidPackage p,
@NonNull PackageSetting pkgSetting, DexoptOptions options) {
+ // System server gets a special path.
+ if (PLATFORM_PACKAGE_NAME.equals(p.getPackageName())) {
+ return mDexManager.dexoptSystemServer(options);
+ }
+
// Select the dex optimizer based on the force parameter.
// Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
// allocate an object here.
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index ebdf85691e58..eb7057dd2994 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -49,6 +49,8 @@ import dalvik.system.VMRuntime;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -437,15 +439,7 @@ public class DexManager {
* because they don't need to be compiled)..
*/
public boolean dexoptSecondaryDex(DexoptOptions options) {
- // Select the dex optimizer based on the force parameter.
- // Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust
- // the necessary dexopt flags to make sure that compilation is not skipped. This avoid
- // passing the force flag through the multitude of layers.
- // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
- // allocate an object here.
- PackageDexOptimizer pdo = options.isForce()
- ? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPackageDexOptimizer)
- : mPackageDexOptimizer;
+ PackageDexOptimizer pdo = getPackageDexOptimizer(options);
String packageName = options.getPackageName();
PackageUseInfo useInfo = getPackageUseInfoOrDefault(packageName);
if (useInfo.getDexUseInfoMap().isEmpty()) {
@@ -486,6 +480,83 @@ public class DexManager {
}
/**
+ * Performs dexopt on system server dex files.
+ *
+ * <p>Verfifies that the package name is {@link PackageManagerService#PLATFORM_PACKAGE_NAME}.
+ *
+ * @return
+ * <p>PackageDexOptimizer.DEX_OPT_SKIPPED if dexopt was skipped because no system server
+ * files were recorded or if no dexopt was needed.
+ * <p>PackageDexOptimizer.DEX_OPT_FAILED if any dexopt operation failed.
+ * <p>PackageDexOptimizer.DEX_OPT_PERFORMED if all dexopt operations succeeded.
+ */
+ public int dexoptSystemServer(DexoptOptions options) {
+ if (!PLATFORM_PACKAGE_NAME.equals(options.getPackageName())) {
+ Slog.wtf(TAG, "Non system server package used when trying to dexopt system server:"
+ + options.getPackageName());
+ return PackageDexOptimizer.DEX_OPT_FAILED;
+ }
+
+ PackageDexOptimizer pdo = getPackageDexOptimizer(options);
+ String packageName = options.getPackageName();
+ PackageUseInfo useInfo = getPackageUseInfoOrDefault(packageName);
+ if (useInfo.getDexUseInfoMap().isEmpty()) {
+ if (DEBUG) {
+ Slog.d(TAG, "No dex files recorded for system server");
+ }
+ // Nothing to compile, return true.
+ return PackageDexOptimizer.DEX_OPT_SKIPPED;
+ }
+
+ boolean usageUpdated = false;
+ int result = PackageDexOptimizer.DEX_OPT_SKIPPED;
+ for (Map.Entry<String, DexUseInfo> entry : useInfo.getDexUseInfoMap().entrySet()) {
+ String dexPath = entry.getKey();
+ DexUseInfo dexUseInfo = entry.getValue();
+ if (!Files.exists(Paths.get(dexPath))) {
+ if (DEBUG) {
+ Slog.w(TAG, "A dex file previously loaded by System Server does not exist "
+ + " anymore: " + dexPath);
+ }
+ usageUpdated = mPackageDexUsage.removeDexFile(
+ packageName, dexPath, dexUseInfo.getOwnerUserId()) || usageUpdated;
+ continue;
+ }
+
+ int newResult = pdo.dexoptSystemServerPath(dexPath, dexUseInfo, options);
+
+ // The end result is:
+ // - FAILED if any path failed,
+ // - PERFORMED if at least one path needed compilation,
+ // - SKIPPED when all paths are up to date
+ if ((result != PackageDexOptimizer.DEX_OPT_FAILED)
+ && (newResult != PackageDexOptimizer.DEX_OPT_SKIPPED)) {
+ result = newResult;
+ }
+ }
+
+ if (usageUpdated) {
+ mPackageDexUsage.maybeWriteAsync();
+ }
+
+ return result;
+ }
+
+ /**
+ * Select the dex optimizer based on the force parameter.
+ * Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust
+ * the necessary dexopt flags to make sure that compilation is not skipped. This avoid
+ * passing the force flag through the multitude of layers.
+ * Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
+ * allocate an object here.
+ */
+ private PackageDexOptimizer getPackageDexOptimizer(DexoptOptions options) {
+ return options.isForce()
+ ? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPackageDexOptimizer)
+ : mPackageDexOptimizer;
+ }
+
+ /**
* Reconcile the information we have about the secondary dex files belonging to
* {@code packagName} and the actual dex files. For all dex files that were
* deleted, update the internal records and delete any generated oat files.