Special handling of priv-apps in PMS.
If pm.dexopt.priv-apps is set to false, don't do any dexopt on it, and
check the APKs have uncompressed and aligned code.
bug: 30972906
bug: 63920015
Test: works as expected when pm.dexopt.priv-apps is true or false
Change-Id: I72a322defb459549617028e030f1aec997223af5
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 5021f2f..7e9596a 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -25,6 +25,7 @@
import android.os.FileUtils;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Log;
@@ -101,7 +102,17 @@
}
static boolean canOptimizePackage(PackageParser.Package pkg) {
- return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
+ // We do not dexopt a package with no code.
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+ return false;
+ }
+
+ // We do not dexopt a priv-app package when pm.dexopt.priv-apps is false.
+ if (pkg.isPrivilegedApp()) {
+ return SystemProperties.getBoolean("pm.dexopt.priv-apps", true);
+ }
+
+ return true;
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9f518c3..6f9c5cb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10137,6 +10137,12 @@
assertPackageIsValid(pkg, policyFlags, scanFlags);
+ if (Build.IS_DEBUGGABLE &&
+ pkg.isPrivilegedApp() &&
+ !SystemProperties.getBoolean("pm.dexopt.priv-apps", true)) {
+ PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg);
+ }
+
// Initialize package source and resource directories
final File scanFile = new File(pkg.codePath);
final File destCodeFile = new File(pkg.applicationInfo.getCodePath());
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 9feee8c..ec9aa63 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -19,6 +19,8 @@
import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
import static com.android.server.pm.PackageManagerService.TAG;
+import com.android.internal.util.ArrayUtils;
+
import android.annotation.NonNull;
import android.app.AppGlobals;
import android.content.Intent;
@@ -30,6 +32,8 @@
import android.system.ErrnoException;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
+import android.util.jar.StrictJarFile;
import dalvik.system.VMRuntime;
import libcore.io.Libcore;
@@ -38,9 +42,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
+import java.util.zip.ZipEntry;
/**
* Class containing helper methods for the PackageManagerService.
@@ -213,4 +219,59 @@
}
return false;
}
+
+ /**
+ * Checks that the archive located at {@code fileName} has uncompressed dex file and so
+ * files that can be direclty mapped.
+ */
+ public static void logApkHasUncompressedCode(String fileName) {
+ StrictJarFile jarFile = null;
+ try {
+ jarFile = new StrictJarFile(fileName,
+ false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
+ Iterator<ZipEntry> it = jarFile.iterator();
+ while (it.hasNext()) {
+ ZipEntry entry = it.next();
+ if (entry.getName().endsWith(".dex")) {
+ if (entry.getMethod() != ZipEntry.STORED) {
+ Slog.wtf(TAG, "APK " + fileName + " has compressed dex code " +
+ entry.getName());
+ } else if ((entry.getDataOffset() & 0x3) != 0) {
+ Slog.wtf(TAG, "APK " + fileName + " has unaligned dex code " +
+ entry.getName());
+ }
+ } else if (entry.getName().endsWith(".so")) {
+ if (entry.getMethod() != ZipEntry.STORED) {
+ Slog.wtf(TAG, "APK " + fileName + " has compressed native code " +
+ entry.getName());
+ } else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
+ Slog.wtf(TAG, "APK " + fileName + " has unaligned native code " +
+ entry.getName());
+ }
+ }
+ }
+ } catch (IOException ignore) {
+ Slog.wtf(TAG, "Error when parsing APK " + fileName);
+ } finally {
+ try {
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ } catch (IOException ignore) {}
+ }
+ return;
+ }
+
+ /**
+ * Checks that the APKs in the given package have uncompressed dex file and so
+ * files that can be direclty mapped.
+ */
+ public static void logPackageHasUncompressedCode(PackageParser.Package pkg) {
+ logApkHasUncompressedCode(pkg.baseCodePath);
+ if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+ for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+ logApkHasUncompressedCode(pkg.splitCodePaths[i]);
+ }
+ }
+ }
}