diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 5021f2f0162d6..7e9596adf1384 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.Environment; 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 @@ public class PackageDexOptimizer { } 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 a2fea493b15fc..7228379bd164e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -10243,6 +10243,12 @@ public class PackageManagerService extends IPackageManager.Stub 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 9feee8c97c0dd..ec9aa6332901e 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 @@ package com.android.server.pm; 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.os.UserHandle; 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.io.IOException; 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 @@ public class PackageManagerServiceUtils { } 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 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]); + } + } + } }