diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 97bc570aff4cf..1d9a582d2fe10 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4970,70 +4970,6 @@ public final class ActivityThread { } } - // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp). - private static File getPrimaryProfileFile(String packageName) { - File profileDir = Environment.getDataProfilesDePackageDirectory( - UserHandle.myUserId(), packageName); - return new File(profileDir, "primary.prof"); - } - - private static void setupJitProfileSupport(LoadedApk loadedApk, File cacheDir) { - if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) { - return; - } - final ApplicationInfo appInfo = loadedApk.getApplicationInfo(); - final List codePaths = new ArrayList<>(); - if ((appInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { - codePaths.add(appInfo.sourceDir); - } - if (appInfo.splitSourceDirs != null) { - Collections.addAll(codePaths, appInfo.splitSourceDirs); - } - - if (codePaths.isEmpty()) { - // If there are no code paths there's no need to setup a profile file and register with - // the runtime, - return; - } - - final File profileFile = getPrimaryProfileFile(loadedApk.mPackageName); - if (!profileFile.exists()) { - FileDescriptor fd = null; - try { - final int permissions = 0600; // read-write for user. - fd = Os.open(profileFile.getAbsolutePath(), OsConstants.O_CREAT, permissions); - Os.fchmod(fd, permissions); - Os.fchown(fd, appInfo.uid, appInfo.uid); - } catch (ErrnoException e) { - Log.v(TAG, "Unable to create jit profile file " - + profileFile + ": " + e.getMessage()); - try { - Os.unlink(profileFile.getAbsolutePath()); - } catch (ErrnoException unlinkErr) { - if (unlinkErr.errno != OsConstants.ENOENT) { - Log.v(TAG, "Unable to unlink jit profile file " - + profileFile + ": " + unlinkErr.getMessage()); - } - } - return; - } finally { - IoUtils.closeQuietly(fd); - } - } - - 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()]), foreignDexProfilesPath); - } - private void updateDefaultDensity() { final int densityDpi = mCurDefaultDisplayDpi; if (!mDensityCompatMode @@ -5259,18 +5195,13 @@ public final class ActivityThread { + "due to missing cache directory"); } - // Setup a location to store generated/compiled graphics code and - // JIT profiling data. Note that this data is stored in a - // device-protected storage area, so these caches must never contain - // user sensitive user data. + // Setup a location to store generated/compiled graphics code. final Context deviceContext = appContext.createDeviceProtectedStorageContext(); final File codeCacheDir = deviceContext.getCodeCacheDir(); if (codeCacheDir != null) { setupGraphicsSupport(data.info, codeCacheDir); - setupJitProfileSupport(data.info, codeCacheDir); } else { - Log.e(TAG, "Unable to setupGraphicsSupport and setupJitProfileSupport " + - "due to missing code-cache directory"); + Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory"); } // Add the lib dir path to hardware renderer so that vulkan layers diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index e090aa442d8ea..849636f5b5dd6 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -29,6 +29,7 @@ import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; import android.content.res.Resources; import android.os.Bundle; +import android.os.Environment; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; @@ -38,6 +39,9 @@ import android.os.StrictMode; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; +import android.system.Os; +import android.system.OsConstants; +import android.system.ErrnoException; import android.text.TextUtils; import android.util.AndroidRuntimeException; import android.util.ArrayMap; @@ -50,6 +54,7 @@ import android.view.DisplayAdjustments; import dalvik.system.VMRuntime; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; @@ -62,6 +67,8 @@ import java.util.Enumeration; import java.util.List; import java.util.Objects; +import libcore.io.IoUtils; + final class IntentReceiverLeaked extends AndroidRuntimeException { public IntentReceiverLeaked(String msg) { super(msg); @@ -488,6 +495,13 @@ public final class LoadedApk { final String add = TextUtils.join(File.pathSeparator, addedPaths); ApplicationLoaders.getDefault().addPath(mClassLoader, add); } + + // Setup jit profile support. + // It is ok to call this multiple times if the application gets updated with new splits. + // The runtime only keeps track of unique code paths and can handle re-registration of + // the same code path. There's no need to pass `addedPaths` since any new code paths + // are already in `mApplicationInfo`. + setupJitProfileSupport(); } public ClassLoader getClassLoader() { @@ -499,6 +513,83 @@ public final class LoadedApk { } } + // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp). + private static File getPrimaryProfileFile(String packageName) { + File profileDir = Environment.getDataProfilesDePackageDirectory( + UserHandle.myUserId(), packageName); + return new File(profileDir, "primary.prof"); + } + + private void setupJitProfileSupport() { + if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) { + return; + } + final List codePaths = new ArrayList<>(); + if ((mApplicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { + codePaths.add(mApplicationInfo.sourceDir); + } + if (mApplicationInfo.splitSourceDirs != null) { + Collections.addAll(codePaths, mApplicationInfo.splitSourceDirs); + } + + if (codePaths.isEmpty()) { + // If there are no code paths there's no need to setup a profile file and register with + // the runtime, + return; + } + + final File profileFile = getPrimaryProfileFile(mPackageName); + if (profileFile.exists()) { + if (!profileFile.canRead() || !profileFile.canWrite()) { + // The apk might be loaded in a context where we don't have permissions + // to track the profile (e.g. when loaded by another app via + // createApplicationContext) + return; + } + } else { + // Profile does not exist. Create it. + FileDescriptor fd = null; + try { + final int permissions = 0600; // read-write for user. + fd = Os.open(profileFile.getAbsolutePath(), OsConstants.O_CREAT, permissions); + Os.fchmod(fd, permissions); + Os.fchown(fd, mApplicationInfo.uid, mApplicationInfo.uid); + } catch (ErrnoException e) { + if (e.errno == OsConstants.EACCES) { + // It can happen that the profile file does not exist but the apk is loaded in a + // context where we don't have permissions (e.g. when loaded by another app via + // createApplicationContext) + return; + } + Log.v(TAG, "Unable to create jit profile file " + + profileFile + ": " + e.getMessage()); + try { + Os.unlink(profileFile.getAbsolutePath()); + } catch (ErrnoException unlinkErr) { + if (unlinkErr.errno != OsConstants.ENOENT) { + Log.v(TAG, "Unable to unlink jit profile file " + + profileFile + ": " + unlinkErr.getMessage()); + } + } + return; + } finally { + IoUtils.closeQuietly(fd); + } + } + + 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(), mApplicationInfo.dataDir, + codePaths.toArray(new String[codePaths.size()]), foreignDexProfilesPath); + } + /** * Setup value for Thread.getContextClassLoader(). If the * package will not run in in a VM with other packages, we set