summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/system-current.txt6
-rw-r--r--core/java/android/content/pm/dex/ArtManager.java109
-rw-r--r--core/java/android/content/pm/dex/IArtManager.aidl38
-rw-r--r--services/core/java/com/android/server/pm/Installer.java6
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtManagerService.java101
5 files changed, 175 insertions, 85 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index b6d8142b2ebd..d2c6bd064ac9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -953,8 +953,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
diff --git a/core/java/android/content/pm/dex/ArtManager.java b/core/java/android/content/pm/dex/ArtManager.java
index f979576e5315..075306366264 100644
--- a/core/java/android/content/pm/dex/ArtManager.java
+++ b/core/java/android/content/pm/dex/ArtManager.java
@@ -16,18 +16,20 @@
package android.content.pm.dex;
+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
@@ -46,6 +48,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;
/**
@@ -56,41 +72,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 {@code handler} using the given {@code callback}.
- * The profile being available as a read-only {@link android.os.ParcelFileDescriptor}.
+ * 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}.
*
- * @param packageName the target package name
- * @param codePath the code path for which the profile should be retrieved
+ * This method will throw {@link IllegalStateException} if
+ * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given
+ * {@code profileType}.
+ *
+ * @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 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();
}
@@ -119,41 +153,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));
}
}
@@ -178,17 +195,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");
}
}
diff --git a/core/java/android/content/pm/dex/IArtManager.aidl b/core/java/android/content/pm/dex/IArtManager.aidl
index 8cbb452344b2..6abfdbab6e26 100644
--- a/core/java/android/content/pm/dex/IArtManager.aidl
+++ b/core/java/android/content/pm/dex/IArtManager.aidl
@@ -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}.
- */
- oneway void snapshotRuntimeProfile(in String packageName,
- in String codePath, in ISnapshotRuntimeProfileCallback callback);
-
- /**
- * Returns true if runtime profiles are enabled, false otherwise.
+ * 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}.
*/
- boolean isRuntimeProfilingEnabled();
+ oneway void snapshotRuntimeProfile(int profileType, in String packageName,
+ in String codePath, in ISnapshotRuntimeProfileCallback callback);
+
+ /**
+ * 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}.
+ *
+ * @param profileType
+ */
+ boolean isRuntimeProfilingEnabled(int profileType);
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 7b02ace2c05f..1c1357bb23fa 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -502,11 +502,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);
}
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index f15dc2d5f8d3..e29027288e9b 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -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;
@@ -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;
@@ -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.
@@ -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")
@@ -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.
@@ -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;
}
@@ -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);
@@ -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();
- return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+ 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);
}
/**