diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f2a8ea5eb1484..0d8069e18b968 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4804,8 +4804,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) { @@ -4848,8 +4849,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.