Loading api/system-current.txt +4 −2 Original line number Diff line number Diff line Loading @@ -1044,8 +1044,10 @@ package android.content.pm { package android.content.pm.dex { public class ArtManager { method public boolean isRuntimeProfilingEnabled(); method public void snapshotRuntimeProfile(java.lang.String, java.lang.String, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback, android.os.Handler); method public boolean isRuntimeProfilingEnabled(int); method public void snapshotRuntimeProfile(int, java.lang.String, java.lang.String, java.util.concurrent.Executor, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback); field public static final int PROFILE_APPS = 0; // 0x0 field public static final int PROFILE_BOOT_IMAGE = 1; // 0x1 field public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; // 0x1 field public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; // 0x2 field public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; // 0x0 Loading core/java/android/content/pm/dex/ArtManager.java +63 −47 Original line number Diff line number Diff line Loading @@ -16,18 +16,21 @@ package android.content.pm.dex; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Slog; import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; /** * Class for retrieving various kinds of information related to the runtime artifacts of Loading @@ -46,6 +49,20 @@ public class ArtManager { /** The snapshot failed because of an internal error (e.g. error during opening profiles). */ public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; /** Constant used for applications profiles. */ public static final int PROFILE_APPS = 0; /** Constant used for the boot image profile. */ public static final int PROFILE_BOOT_IMAGE = 1; /** @hide */ @IntDef(flag = true, prefix = { "PROFILE_" }, value = { PROFILE_APPS, PROFILE_BOOT_IMAGE, }) @Retention(RetentionPolicy.SOURCE) public @interface ProfileType {} private IArtManager mArtManager; /** Loading @@ -56,41 +73,59 @@ public class ArtManager { } /** * Snapshots the runtime profile for an apk belonging to the package {@code packageName}. * The apk is identified by {@code codePath}. The calling process must have * {@code android.permission.READ_RUNTIME_PROFILE} permission. * Snapshots a runtime profile according to the {@code profileType} parameter. * * If {@code profileType} is {@link ArtManager#PROFILE_APPS} the method will snapshot * the profile for for an apk belonging to the package {@code packageName}. * The apk is identified by {@code codePath}. * * If {@code profileType} is {@code ArtManager.PROFILE_BOOT_IMAGE} the method will snapshot * the profile for the boot image. In this case {@code codePath can be null}. The parameters * {@code packageName} and {@code codePath} are ignored. *u * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. * * The result will be posted on the {@code executor} using the given {@code callback}. * The profile will be available as a read-only {@link android.os.ParcelFileDescriptor}. * * The result will be posted on {@code handler} using the given {@code callback}. * The profile being available as a read-only {@link android.os.ParcelFileDescriptor}. * This method will throw {@link IllegalStateException} if * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given * {@code profileType}. * * @param packageName the target package name * @param codePath the code path for which the profile should be retrieved * @param profileType the type of profile that should be snapshot (boot image or app) * @param packageName the target package name or null if the target is the boot image * @param codePath the code path for which the profile should be retrieved or null if * the target is the boot image * @param callback the callback which should be used for the result * @param handler the handler which should be used to post the result * @param executor the executor which should be used to post the result */ @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES) public void snapshotRuntimeProfile(@NonNull String packageName, @NonNull String codePath, @NonNull SnapshotRuntimeProfileCallback callback, @NonNull Handler handler) { public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName, @Nullable String codePath, @NonNull @CallbackExecutor Executor executor, @NonNull SnapshotRuntimeProfileCallback callback) { Slog.d(TAG, "Requesting profile snapshot for " + packageName + ":" + codePath); SnapshotRuntimeProfileCallbackDelegate delegate = new SnapshotRuntimeProfileCallbackDelegate(callback, handler.getLooper()); new SnapshotRuntimeProfileCallbackDelegate(callback, executor); try { mArtManager.snapshotRuntimeProfile(packageName, codePath, delegate); mArtManager.snapshotRuntimeProfile(profileType, packageName, codePath, delegate); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } } /** * Returns true if runtime profiles are enabled, false otherwise. * Returns true if runtime profiles are enabled for the given type, false otherwise. * * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. * * @param profileType can be either {@link ArtManager#PROFILE_APPS} * or {@link ArtManager#PROFILE_BOOT_IMAGE} */ @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES) public boolean isRuntimeProfilingEnabled() { public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) { try { return mArtManager.isRuntimeProfilingEnabled(); return mArtManager.isRuntimeProfilingEnabled(profileType); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } Loading Loading @@ -119,41 +154,24 @@ public class ArtManager { } private static class SnapshotRuntimeProfileCallbackDelegate extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub implements Handler.Callback { private static final int MSG_SNAPSHOT_OK = 1; private static final int MSG_ERROR = 2; extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub { private final ArtManager.SnapshotRuntimeProfileCallback mCallback; private final Handler mHandler; private final Executor mExecutor; private SnapshotRuntimeProfileCallbackDelegate( ArtManager.SnapshotRuntimeProfileCallback callback, Looper looper) { ArtManager.SnapshotRuntimeProfileCallback callback, Executor executor) { mCallback = callback; mHandler = new Handler(looper, this); mExecutor = executor; } @Override public void onSuccess(ParcelFileDescriptor profileReadFd) { mHandler.obtainMessage(MSG_SNAPSHOT_OK, profileReadFd).sendToTarget(); public void onSuccess(final ParcelFileDescriptor profileReadFd) { mExecutor.execute(() -> mCallback.onSuccess(profileReadFd)); } @Override public void onError(int errCode) { mHandler.obtainMessage(MSG_ERROR, errCode, 0).sendToTarget(); } @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_SNAPSHOT_OK: mCallback.onSuccess((ParcelFileDescriptor) msg.obj); break; case MSG_ERROR: mCallback.onError(msg.arg1); break; default: return false; } return true; mExecutor.execute(() -> mCallback.onError(errCode)); } } Loading @@ -178,17 +196,15 @@ public class ArtManager { } /** * Return the snapshot profile file for the given package and split. * Return the snapshot profile file for the given package and profile name. * * KEEP in sync with installd dexopt.cpp. * TODO(calin): inject the snapshot profile name from PM to avoid the dependency. * * @hide */ public static File getProfileSnapshotFile(String packageName, String splitName) { public static File getProfileSnapshotFileForName(String packageName, String profileName) { File profileDir = Environment.getDataRefProfilesDePackageDirectory(packageName); String snapshotFile = getProfileName(splitName) + ".snapshot"; return new File(profileDir, snapshotFile); return new File(profileDir, profileName + ".snapshot"); } } core/java/android/content/pm/dex/IArtManager.aidl +26 −12 Original line number Diff line number Diff line Loading @@ -25,20 +25,34 @@ import android.content.pm.dex.ISnapshotRuntimeProfileCallback; */ interface IArtManager { /** * Snapshots the runtime profile for an apk belonging to the package {@param packageName}. * The apk is identified by {@param codePath}. The calling process must have * {@code android.permission.READ_RUNTIME_PROFILE} permission. * Snapshots a runtime profile according to the {@code profileType} parameter. * * The result will be posted on {@param callback} with the profile being available as a * read-only {@link android.os.ParcelFileDescriptor}. * If {@code profileType} is {@link ArtManager#PROFILE_APPS} the method will snapshot * the profile for for an apk belonging to the package {@code packageName}. * The apk is identified by {@code codePath}. * * If {@code profileType} is {@code ArtManager.PROFILE_BOOT_IMAGE} the method will snapshot * the profile for the boot image. In this case {@code codePath can be null}. The parameters * {@code packageName} and {@code codePath} are ignored. * * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. * * The result will be posted on the {@code executor} using the given {@code callback}. * The profile will be available as a read-only {@link android.os.ParcelFileDescriptor}. * * This method will throw {@link IllegalStateException} if * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given * {@code profileType}. */ oneway void snapshotRuntimeProfile(in String packageName, oneway void snapshotRuntimeProfile(int profileType, in String packageName, in String codePath, in ISnapshotRuntimeProfileCallback callback); /** * Returns true if runtime profiles are enabled, false otherwise. * Returns true if runtime profiles are enabled for the given type, false otherwise. * The type can be can be either {@code ArtManager.PROFILE_APPS} * or {@code ArtManager.PROFILE_BOOT_IMAGE}. * * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. * @param profileType */ boolean isRuntimeProfilingEnabled(); boolean isRuntimeProfilingEnabled(int profileType); } services/core/java/com/android/server/pm/Installer.java +3 −3 Original line number Diff line number Diff line Loading @@ -526,11 +526,11 @@ public class Installer extends SystemService { } } public boolean createProfileSnapshot(int appId, String packageName, String profileName) throws InstallerException { public boolean createProfileSnapshot(int appId, String packageName, String profileName, String classpath) throws InstallerException { if (!checkBeforeRemote()) return false; try { return mInstalld.createProfileSnapshot(appId, packageName, profileName); return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath); } catch (Exception e) { throw InstallerException.from(e); } Loading services/core/java/com/android/server/pm/dex/ArtManagerService.java +80 −21 Original line number Diff line number Diff line Loading @@ -23,8 +23,10 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.dex.ArtManager; import android.content.pm.dex.ArtManager.ProfileType; import android.content.pm.dex.DexMetadataHelper; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.ParcelFileDescriptor; import android.os.RemoteException; Loading @@ -32,6 +34,7 @@ import android.content.pm.IPackageManager; import android.content.pm.dex.ISnapshotRuntimeProfileCallback; import android.os.SystemProperties; import android.os.UserHandle; import android.system.Os; import android.util.ArrayMap; import android.util.Slog; Loading @@ -43,6 +46,9 @@ import com.android.server.pm.Installer; import com.android.server.pm.Installer.InstallerException; import java.io.File; import java.io.FileNotFoundException; import libcore.io.IoUtils; import libcore.util.NonNull; import libcore.util.Nullable; /** * A system service that provides access to runtime and compiler artifacts. Loading @@ -62,6 +68,12 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { private static boolean DEBUG = false; private static boolean DEBUG_IGNORE_PERMISSIONS = false; // Package name used to create the profile directory layout when // taking a snapshot of the boot image profile. private static final String BOOT_IMAGE_ANDROID_PACKAGE = "android"; // Profile name used for the boot image profile. private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof"; private final IPackageManager mPackageManager; private final Object mInstallLock; @GuardedBy("mInstallLock") Loading @@ -77,20 +89,36 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { } @Override public void snapshotRuntimeProfile(String packageName, String codePath, ISnapshotRuntimeProfileCallback callback) { public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName, @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback) { // Sanity checks on the arguments. Preconditions.checkStringNotEmpty(packageName); Preconditions.checkStringNotEmpty(codePath); Preconditions.checkNotNull(callback); // Verify that the caller has the right permissions. checkReadRuntimeProfilePermission(); boolean bootImageProfile = profileType == ArtManager.PROFILE_BOOT_IMAGE; if (!bootImageProfile) { Preconditions.checkStringNotEmpty(codePath); Preconditions.checkStringNotEmpty(packageName); } // Verify that the caller has the right permissions and that the runtime profiling is // enabled. The call to isRuntimePermissions will checkReadRuntimeProfilePermission. if (!isRuntimeProfilingEnabled(profileType)) { throw new IllegalStateException("Runtime profiling is not enabled for " + profileType); } if (DEBUG) { Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath); } if (bootImageProfile) { snapshotBootImageProfile(callback); } else { snapshotAppProfile(packageName, codePath, callback); } } private void snapshotAppProfile(String packageName, String codePath, ISnapshotRuntimeProfileCallback callback) { PackageInfo info = null; try { // Note that we use the default user 0 to retrieve the package info. Loading Loading @@ -127,18 +155,25 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { } // All good, create the profile snapshot. createProfileSnapshot(packageName, splitName, callback, info); int appId = UserHandle.getAppId(info.applicationInfo.uid); if (appId < 0) { postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); Slog.wtf(TAG, "AppId is -1 for package: " + packageName); return; } createProfileSnapshot(packageName, ArtManager.getProfileName(splitName), codePath, appId, callback); // Destroy the snapshot, we no longer need it. destroyProfileSnapshot(packageName, splitName); destroyProfileSnapshot(packageName, ArtManager.getProfileName(splitName)); } private void createProfileSnapshot(String packageName, String splitName, ISnapshotRuntimeProfileCallback callback, PackageInfo info) { private void createProfileSnapshot(String packageName, String profileName, String classpath, int appId, ISnapshotRuntimeProfileCallback callback) { // Ask the installer to snapshot the profile. synchronized (mInstallLock) { try { if (!mInstaller.createProfileSnapshot(UserHandle.getAppId(info.applicationInfo.uid), packageName, ArtManager.getProfileName(splitName))) { if (!mInstaller.createProfileSnapshot(appId, packageName, profileName, classpath)) { postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); return; } Loading @@ -149,8 +184,9 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { } // Open the snapshot and invoke the callback. File snapshotProfile = ArtManager.getProfileSnapshotFile(packageName, splitName); ParcelFileDescriptor fd; File snapshotProfile = ArtManager.getProfileSnapshotFileForName(packageName, profileName); ParcelFileDescriptor fd = null; try { fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY); postSuccess(packageName, fd, callback); Loading @@ -158,31 +194,54 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":" + snapshotProfile, e); postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); } finally { IoUtils.closeQuietly(fd); } } private void destroyProfileSnapshot(String packageName, String splitName) { private void destroyProfileSnapshot(String packageName, String profileName) { if (DEBUG) { Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + splitName); Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + profileName); } synchronized (mInstallLock) { try { mInstaller.destroyProfileSnapshot(packageName, ArtManager.getProfileName(splitName)); mInstaller.destroyProfileSnapshot(packageName, profileName); } catch (InstallerException e) { Slog.e(TAG, "Failed to destroy profile snapshot for " + packageName + ":" + splitName, e); packageName + ":" + profileName, e); } } } @Override public boolean isRuntimeProfilingEnabled() { public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) { // Verify that the caller has the right permissions. checkReadRuntimeProfilePermission(); switch (profileType) { case ArtManager.PROFILE_APPS : return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); case ArtManager.PROFILE_BOOT_IMAGE: return (Build.IS_USERDEBUG || Build.IS_ENG) && SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false) && SystemProperties.getBoolean("dalvik.vm.profilebootimage", false); default: throw new IllegalArgumentException("Invalid profile type:" + profileType); } } private void snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback) { // Combine the profiles for boot classpath and system server classpath. // This avoids having yet another type of profiles and simplifies the processing. String classpath = String.join(":", Os.getenv("BOOTCLASSPATH"), Os.getenv("SYSTEMSERVERCLASSPATH")); // Create the snapshot. createProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME, classpath, /*appId*/ -1, callback); // Destroy the snapshot, we no longer need it. destroyProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME); } /** Loading Loading
api/system-current.txt +4 −2 Original line number Diff line number Diff line Loading @@ -1044,8 +1044,10 @@ package android.content.pm { package android.content.pm.dex { public class ArtManager { method public boolean isRuntimeProfilingEnabled(); method public void snapshotRuntimeProfile(java.lang.String, java.lang.String, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback, android.os.Handler); method public boolean isRuntimeProfilingEnabled(int); method public void snapshotRuntimeProfile(int, java.lang.String, java.lang.String, java.util.concurrent.Executor, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback); field public static final int PROFILE_APPS = 0; // 0x0 field public static final int PROFILE_BOOT_IMAGE = 1; // 0x1 field public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; // 0x1 field public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; // 0x2 field public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; // 0x0 Loading
core/java/android/content/pm/dex/ArtManager.java +63 −47 Original line number Diff line number Diff line Loading @@ -16,18 +16,21 @@ package android.content.pm.dex; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Slog; import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; /** * Class for retrieving various kinds of information related to the runtime artifacts of Loading @@ -46,6 +49,20 @@ public class ArtManager { /** The snapshot failed because of an internal error (e.g. error during opening profiles). */ public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; /** Constant used for applications profiles. */ public static final int PROFILE_APPS = 0; /** Constant used for the boot image profile. */ public static final int PROFILE_BOOT_IMAGE = 1; /** @hide */ @IntDef(flag = true, prefix = { "PROFILE_" }, value = { PROFILE_APPS, PROFILE_BOOT_IMAGE, }) @Retention(RetentionPolicy.SOURCE) public @interface ProfileType {} private IArtManager mArtManager; /** Loading @@ -56,41 +73,59 @@ public class ArtManager { } /** * Snapshots the runtime profile for an apk belonging to the package {@code packageName}. * The apk is identified by {@code codePath}. The calling process must have * {@code android.permission.READ_RUNTIME_PROFILE} permission. * Snapshots a runtime profile according to the {@code profileType} parameter. * * If {@code profileType} is {@link ArtManager#PROFILE_APPS} the method will snapshot * the profile for for an apk belonging to the package {@code packageName}. * The apk is identified by {@code codePath}. * * If {@code profileType} is {@code ArtManager.PROFILE_BOOT_IMAGE} the method will snapshot * the profile for the boot image. In this case {@code codePath can be null}. The parameters * {@code packageName} and {@code codePath} are ignored. *u * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. * * The result will be posted on the {@code executor} using the given {@code callback}. * The profile will be available as a read-only {@link android.os.ParcelFileDescriptor}. * * The result will be posted on {@code handler} using the given {@code callback}. * The profile being available as a read-only {@link android.os.ParcelFileDescriptor}. * This method will throw {@link IllegalStateException} if * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given * {@code profileType}. * * @param packageName the target package name * @param codePath the code path for which the profile should be retrieved * @param profileType the type of profile that should be snapshot (boot image or app) * @param packageName the target package name or null if the target is the boot image * @param codePath the code path for which the profile should be retrieved or null if * the target is the boot image * @param callback the callback which should be used for the result * @param handler the handler which should be used to post the result * @param executor the executor which should be used to post the result */ @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES) public void snapshotRuntimeProfile(@NonNull String packageName, @NonNull String codePath, @NonNull SnapshotRuntimeProfileCallback callback, @NonNull Handler handler) { public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName, @Nullable String codePath, @NonNull @CallbackExecutor Executor executor, @NonNull SnapshotRuntimeProfileCallback callback) { Slog.d(TAG, "Requesting profile snapshot for " + packageName + ":" + codePath); SnapshotRuntimeProfileCallbackDelegate delegate = new SnapshotRuntimeProfileCallbackDelegate(callback, handler.getLooper()); new SnapshotRuntimeProfileCallbackDelegate(callback, executor); try { mArtManager.snapshotRuntimeProfile(packageName, codePath, delegate); mArtManager.snapshotRuntimeProfile(profileType, packageName, codePath, delegate); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } } /** * Returns true if runtime profiles are enabled, false otherwise. * Returns true if runtime profiles are enabled for the given type, false otherwise. * * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. * * @param profileType can be either {@link ArtManager#PROFILE_APPS} * or {@link ArtManager#PROFILE_BOOT_IMAGE} */ @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES) public boolean isRuntimeProfilingEnabled() { public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) { try { return mArtManager.isRuntimeProfilingEnabled(); return mArtManager.isRuntimeProfilingEnabled(profileType); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } Loading Loading @@ -119,41 +154,24 @@ public class ArtManager { } private static class SnapshotRuntimeProfileCallbackDelegate extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub implements Handler.Callback { private static final int MSG_SNAPSHOT_OK = 1; private static final int MSG_ERROR = 2; extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub { private final ArtManager.SnapshotRuntimeProfileCallback mCallback; private final Handler mHandler; private final Executor mExecutor; private SnapshotRuntimeProfileCallbackDelegate( ArtManager.SnapshotRuntimeProfileCallback callback, Looper looper) { ArtManager.SnapshotRuntimeProfileCallback callback, Executor executor) { mCallback = callback; mHandler = new Handler(looper, this); mExecutor = executor; } @Override public void onSuccess(ParcelFileDescriptor profileReadFd) { mHandler.obtainMessage(MSG_SNAPSHOT_OK, profileReadFd).sendToTarget(); public void onSuccess(final ParcelFileDescriptor profileReadFd) { mExecutor.execute(() -> mCallback.onSuccess(profileReadFd)); } @Override public void onError(int errCode) { mHandler.obtainMessage(MSG_ERROR, errCode, 0).sendToTarget(); } @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_SNAPSHOT_OK: mCallback.onSuccess((ParcelFileDescriptor) msg.obj); break; case MSG_ERROR: mCallback.onError(msg.arg1); break; default: return false; } return true; mExecutor.execute(() -> mCallback.onError(errCode)); } } Loading @@ -178,17 +196,15 @@ public class ArtManager { } /** * Return the snapshot profile file for the given package and split. * Return the snapshot profile file for the given package and profile name. * * KEEP in sync with installd dexopt.cpp. * TODO(calin): inject the snapshot profile name from PM to avoid the dependency. * * @hide */ public static File getProfileSnapshotFile(String packageName, String splitName) { public static File getProfileSnapshotFileForName(String packageName, String profileName) { File profileDir = Environment.getDataRefProfilesDePackageDirectory(packageName); String snapshotFile = getProfileName(splitName) + ".snapshot"; return new File(profileDir, snapshotFile); return new File(profileDir, profileName + ".snapshot"); } }
core/java/android/content/pm/dex/IArtManager.aidl +26 −12 Original line number Diff line number Diff line Loading @@ -25,20 +25,34 @@ import android.content.pm.dex.ISnapshotRuntimeProfileCallback; */ interface IArtManager { /** * Snapshots the runtime profile for an apk belonging to the package {@param packageName}. * The apk is identified by {@param codePath}. The calling process must have * {@code android.permission.READ_RUNTIME_PROFILE} permission. * Snapshots a runtime profile according to the {@code profileType} parameter. * * The result will be posted on {@param callback} with the profile being available as a * read-only {@link android.os.ParcelFileDescriptor}. * If {@code profileType} is {@link ArtManager#PROFILE_APPS} the method will snapshot * the profile for for an apk belonging to the package {@code packageName}. * The apk is identified by {@code codePath}. * * If {@code profileType} is {@code ArtManager.PROFILE_BOOT_IMAGE} the method will snapshot * the profile for the boot image. In this case {@code codePath can be null}. The parameters * {@code packageName} and {@code codePath} are ignored. * * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. * * The result will be posted on the {@code executor} using the given {@code callback}. * The profile will be available as a read-only {@link android.os.ParcelFileDescriptor}. * * This method will throw {@link IllegalStateException} if * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given * {@code profileType}. */ oneway void snapshotRuntimeProfile(in String packageName, oneway void snapshotRuntimeProfile(int profileType, in String packageName, in String codePath, in ISnapshotRuntimeProfileCallback callback); /** * Returns true if runtime profiles are enabled, false otherwise. * Returns true if runtime profiles are enabled for the given type, false otherwise. * The type can be can be either {@code ArtManager.PROFILE_APPS} * or {@code ArtManager.PROFILE_BOOT_IMAGE}. * * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. * @param profileType */ boolean isRuntimeProfilingEnabled(); boolean isRuntimeProfilingEnabled(int profileType); }
services/core/java/com/android/server/pm/Installer.java +3 −3 Original line number Diff line number Diff line Loading @@ -526,11 +526,11 @@ public class Installer extends SystemService { } } public boolean createProfileSnapshot(int appId, String packageName, String profileName) throws InstallerException { public boolean createProfileSnapshot(int appId, String packageName, String profileName, String classpath) throws InstallerException { if (!checkBeforeRemote()) return false; try { return mInstalld.createProfileSnapshot(appId, packageName, profileName); return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath); } catch (Exception e) { throw InstallerException.from(e); } Loading
services/core/java/com/android/server/pm/dex/ArtManagerService.java +80 −21 Original line number Diff line number Diff line Loading @@ -23,8 +23,10 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.dex.ArtManager; import android.content.pm.dex.ArtManager.ProfileType; import android.content.pm.dex.DexMetadataHelper; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.ParcelFileDescriptor; import android.os.RemoteException; Loading @@ -32,6 +34,7 @@ import android.content.pm.IPackageManager; import android.content.pm.dex.ISnapshotRuntimeProfileCallback; import android.os.SystemProperties; import android.os.UserHandle; import android.system.Os; import android.util.ArrayMap; import android.util.Slog; Loading @@ -43,6 +46,9 @@ import com.android.server.pm.Installer; import com.android.server.pm.Installer.InstallerException; import java.io.File; import java.io.FileNotFoundException; import libcore.io.IoUtils; import libcore.util.NonNull; import libcore.util.Nullable; /** * A system service that provides access to runtime and compiler artifacts. Loading @@ -62,6 +68,12 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { private static boolean DEBUG = false; private static boolean DEBUG_IGNORE_PERMISSIONS = false; // Package name used to create the profile directory layout when // taking a snapshot of the boot image profile. private static final String BOOT_IMAGE_ANDROID_PACKAGE = "android"; // Profile name used for the boot image profile. private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof"; private final IPackageManager mPackageManager; private final Object mInstallLock; @GuardedBy("mInstallLock") Loading @@ -77,20 +89,36 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { } @Override public void snapshotRuntimeProfile(String packageName, String codePath, ISnapshotRuntimeProfileCallback callback) { public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName, @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback) { // Sanity checks on the arguments. Preconditions.checkStringNotEmpty(packageName); Preconditions.checkStringNotEmpty(codePath); Preconditions.checkNotNull(callback); // Verify that the caller has the right permissions. checkReadRuntimeProfilePermission(); boolean bootImageProfile = profileType == ArtManager.PROFILE_BOOT_IMAGE; if (!bootImageProfile) { Preconditions.checkStringNotEmpty(codePath); Preconditions.checkStringNotEmpty(packageName); } // Verify that the caller has the right permissions and that the runtime profiling is // enabled. The call to isRuntimePermissions will checkReadRuntimeProfilePermission. if (!isRuntimeProfilingEnabled(profileType)) { throw new IllegalStateException("Runtime profiling is not enabled for " + profileType); } if (DEBUG) { Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath); } if (bootImageProfile) { snapshotBootImageProfile(callback); } else { snapshotAppProfile(packageName, codePath, callback); } } private void snapshotAppProfile(String packageName, String codePath, ISnapshotRuntimeProfileCallback callback) { PackageInfo info = null; try { // Note that we use the default user 0 to retrieve the package info. Loading Loading @@ -127,18 +155,25 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { } // All good, create the profile snapshot. createProfileSnapshot(packageName, splitName, callback, info); int appId = UserHandle.getAppId(info.applicationInfo.uid); if (appId < 0) { postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); Slog.wtf(TAG, "AppId is -1 for package: " + packageName); return; } createProfileSnapshot(packageName, ArtManager.getProfileName(splitName), codePath, appId, callback); // Destroy the snapshot, we no longer need it. destroyProfileSnapshot(packageName, splitName); destroyProfileSnapshot(packageName, ArtManager.getProfileName(splitName)); } private void createProfileSnapshot(String packageName, String splitName, ISnapshotRuntimeProfileCallback callback, PackageInfo info) { private void createProfileSnapshot(String packageName, String profileName, String classpath, int appId, ISnapshotRuntimeProfileCallback callback) { // Ask the installer to snapshot the profile. synchronized (mInstallLock) { try { if (!mInstaller.createProfileSnapshot(UserHandle.getAppId(info.applicationInfo.uid), packageName, ArtManager.getProfileName(splitName))) { if (!mInstaller.createProfileSnapshot(appId, packageName, profileName, classpath)) { postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); return; } Loading @@ -149,8 +184,9 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { } // Open the snapshot and invoke the callback. File snapshotProfile = ArtManager.getProfileSnapshotFile(packageName, splitName); ParcelFileDescriptor fd; File snapshotProfile = ArtManager.getProfileSnapshotFileForName(packageName, profileName); ParcelFileDescriptor fd = null; try { fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY); postSuccess(packageName, fd, callback); Loading @@ -158,31 +194,54 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":" + snapshotProfile, e); postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); } finally { IoUtils.closeQuietly(fd); } } private void destroyProfileSnapshot(String packageName, String splitName) { private void destroyProfileSnapshot(String packageName, String profileName) { if (DEBUG) { Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + splitName); Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + profileName); } synchronized (mInstallLock) { try { mInstaller.destroyProfileSnapshot(packageName, ArtManager.getProfileName(splitName)); mInstaller.destroyProfileSnapshot(packageName, profileName); } catch (InstallerException e) { Slog.e(TAG, "Failed to destroy profile snapshot for " + packageName + ":" + splitName, e); packageName + ":" + profileName, e); } } } @Override public boolean isRuntimeProfilingEnabled() { public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) { // Verify that the caller has the right permissions. checkReadRuntimeProfilePermission(); switch (profileType) { case ArtManager.PROFILE_APPS : return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); case ArtManager.PROFILE_BOOT_IMAGE: return (Build.IS_USERDEBUG || Build.IS_ENG) && SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false) && SystemProperties.getBoolean("dalvik.vm.profilebootimage", false); default: throw new IllegalArgumentException("Invalid profile type:" + profileType); } } private void snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback) { // Combine the profiles for boot classpath and system server classpath. // This avoids having yet another type of profiles and simplifies the processing. String classpath = String.join(":", Os.getenv("BOOTCLASSPATH"), Os.getenv("SYSTEMSERVERCLASSPATH")); // Create the snapshot. createProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME, classpath, /*appId*/ -1, callback); // Destroy the snapshot, we no longer need it. destroyProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME); } /** Loading