From d479b52d12fc782f18df6b5ae15c19e022f0ec14 Mon Sep 17 00:00:00 2001 From: Calin Juravle Date: Wed, 24 Feb 2016 16:22:03 +0000 Subject: [PATCH] Restrict the cases when we profile guided compile an apk Do not use profile guided compilation if the apk is loaded by another app. The decision if an apk was used or not by another app is done by looking into the foreign profile directory. Apks which where loaded in others apps will have a file marker in the profile directory. The marker is named after the canonical location of the apk file where '/' is replaced by '@'. Also, refactor the profile paths to the Environment. Bug: 27334750 Bug: 26080105 Change-Id: Ic2ac5a7a231670ecb4462166c34fdd5b4c631178 --- core/java/android/app/ActivityThread.java | 16 +++++++++-- core/java/android/os/Environment.java | 14 ++++++++++ .../server/pm/PackageDexOptimizer.java | 28 ++++++++++++++++++- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 02b94de925091..3a8085a12bfb6 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4776,8 +4776,9 @@ public final class ActivityThread { // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp). private static File getPrimaryProfileFile(String packageName) { - return new File("/data/misc/profiles/cur/" + UserHandle.myUserId() + - "/" + packageName + "/primary.prof"); + File profileDir = Environment.getDataProfilesDePackageDirectory( + UserHandle.myUserId(), packageName); + return new File(profileDir, "primary.prof"); } private static void setupJitProfileSupport(LoadedApk loadedApk, File cacheDir) { @@ -4820,8 +4821,17 @@ public final class ActivityThread { } } + final File foreignDexProfilesFile = + Environment.getDataProfilesDeForeignDexDirectory(UserHandle.myUserId()); + String foreignDexProfilesPath = null; + if (!foreignDexProfilesFile.exists()) { + Log.v(TAG, "ForeignDexProfilesPath does not exists:" + + foreignDexProfilesFile.getPath()); + } else { + foreignDexProfilesPath = foreignDexProfilesFile.getAbsolutePath(); + } VMRuntime.registerAppInfo(profileFile.getAbsolutePath(), appInfo.dataDir, - codePaths.toArray(new String[codePaths.size()])); + codePaths.toArray(new String[codePaths.size()]), foreignDexProfilesPath); } private void updateDefaultDensity() { diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 1085b1e9dc6b6..894bfc904bb61 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -258,6 +258,20 @@ public class Environment { return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId)); } + private static File getDataProfilesDeDirectory(int userId) { + return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId)); + } + + /** {@hide} */ + public static File getDataProfilesDePackageDirectory(int userId, String packageName) { + return buildPath(getDataProfilesDeDirectory(userId), packageName); + } + + /** {@hide} */ + public static File getDataProfilesDeForeignDexDirectory(int userId) { + return buildPath(getDataProfilesDeDirectory(userId), "foreign-dex"); + } + /** {@hide} */ public static File getDataAppDirectory(String volumeUuid) { return new File(getDataDirectory(volumeUuid), "app"); diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index a3af561bf44f8..a084d866ec64e 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageParser; import android.content.pm.PackageParser.Package; +import android.os.Environment; import android.os.PowerManager; import android.os.UserHandle; import android.os.WorkSource; @@ -164,6 +165,10 @@ class PackageDexOptimizer { } for (String path : paths) { + if (useProfiles && isUsedByOtherApps(path)) { + // We cannot use profile guided compilation if the apk was used by another app. + useProfiles = false; + } int dexoptNeeded; try { @@ -204,8 +209,10 @@ class PackageDexOptimizer { + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable + " extractOnly=" + extractOnly + " oatDir = " + oatDir); final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + // Profile guide compiled oat files should not be public. + final boolean isPublic = !pkg.isForwardLocked() && !useProfiles; final int dexFlags = adjustDexoptFlags( - (!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0) + ( isPublic ? DEXOPT_PUBLIC : 0) | (vmSafeMode ? DEXOPT_SAFEMODE : 0) | (debuggable ? DEXOPT_DEBUGGABLE : 0) | (extractOnly ? DEXOPT_EXTRACTONLY : 0) @@ -275,6 +282,25 @@ class PackageDexOptimizer { mSystemReady = true; } + private boolean isUsedByOtherApps(String apkPath) { + try { + apkPath = new File(apkPath).getCanonicalPath(); + } catch (IOException e) { + // Log an error but continue without it. + Slog.w(TAG, "Failed to get canonical path", e); + } + String useMarker = apkPath.replace('/', '@'); + final int[] currentUserIds = UserManagerService.getInstance().getUserIds(); + for (int i = 0; i < currentUserIds.length; i++) { + File profileDir = Environment.getDataProfilesDeForeignDexDirectory(currentUserIds[i]); + File foreignUseMark = new File(profileDir, useMarker); + if (foreignUseMark.exists()) { + return true; + } + } + return false; + } + /** * A specialized PackageDexOptimizer that overrides already-installed checks, forcing a * dexopt path.