diff options
-rw-r--r-- | Android.bp | 2 | ||||
-rw-r--r-- | api/system-current.txt | 20 | ||||
-rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 17 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 3 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageManager.java | 11 | ||||
-rw-r--r-- | core/java/android/content/pm/dex/ArtManager.java | 156 | ||||
-rw-r--r-- | core/java/android/content/pm/dex/IArtManager.aidl | 44 | ||||
-rw-r--r-- | core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl | 29 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 5 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 24 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/dex/ArtManagerService.java | 155 | ||||
-rw-r--r-- | test-mock/src/android/test/mock/MockPackageManager.java | 9 |
12 files changed, 461 insertions, 14 deletions
diff --git a/Android.bp b/Android.bp index 32adc1c5a5de..c6c966c0e234 100644 --- a/Android.bp +++ b/Android.bp @@ -134,6 +134,8 @@ java_library { "core/java/android/content/pm/IPackageStatsObserver.aidl", "core/java/android/content/pm/IPinItemRequest.aidl", "core/java/android/content/pm/IShortcutService.aidl", + "core/java/android/content/pm/dex/IArtManager.aidl", + "core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl", "core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl", "core/java/android/database/IContentObserver.aidl", ":libcamera_client_aidl", diff --git a/api/system-current.txt b/api/system-current.txt index 16404e47ebec..abb789d33288 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -126,6 +126,7 @@ package android { field public static final java.lang.String READ_PRINT_SERVICES = "android.permission.READ_PRINT_SERVICES"; field public static final java.lang.String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS"; field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE"; + field public static final java.lang.String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES"; field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES"; field public static final java.lang.String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL"; field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL"; @@ -843,6 +844,7 @@ package android.content.pm { public abstract class PackageManager { method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String); + method public android.content.pm.dex.ArtManager getArtManager(); method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int); method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int); method public abstract android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String); @@ -950,6 +952,24 @@ 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); + 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 + } + + public static abstract class ArtManager.SnapshotRuntimeProfileCallback { + ctor public ArtManager.SnapshotRuntimeProfileCallback(); + method public abstract void onError(int); + method public abstract void onSuccess(android.os.ParcelFileDescriptor); + } + +} + package android.content.pm.permission { public final class RuntimePermissionPresentationInfo implements android.os.Parcelable { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 005b7c389b26..1dbdb59ebcce 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -55,6 +55,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; +import android.content.pm.dex.ArtManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Bitmap; @@ -121,6 +122,8 @@ public class ApplicationPackageManager extends PackageManager { private UserManager mUserManager; @GuardedBy("mLock") private PackageInstaller mInstaller; + @GuardedBy("mLock") + private ArtManager mArtManager; @GuardedBy("mDelegates") private final ArrayList<MoveCallbackDelegate> mDelegates = new ArrayList<>(); @@ -2750,4 +2753,18 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowAsRuntimeException(); } } + + @Override + public ArtManager getArtManager() { + synchronized (mLock) { + if (mArtManager == null) { + try { + mArtManager = new ArtManager(mPM.getArtManager()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return mArtManager; + } + } } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 64d33d543e4a..56a0def27602 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -48,6 +48,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; +import android.content.pm.dex.IArtManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; @@ -657,4 +658,6 @@ interface IPackageManager { ComponentName getInstantAppInstallerComponent(); String getInstantAppAndroidId(String packageName, int userId); + + IArtManager getArtManager(); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index f796aabee2d1..a5cc902c95c4 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -42,6 +42,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.dex.ArtManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Rect; @@ -5842,4 +5843,14 @@ public abstract class PackageManager { @SystemApi public abstract void registerDexModule(String dexModulePath, @Nullable DexModuleRegisterCallback callback); + + /** + * Returns the {@link ArtManager} associated with this package manager. + * + * @hide + */ + @SystemApi + public @NonNull ArtManager getArtManager() { + throw new UnsupportedOperationException("getArtManager not implemented in subclass"); + } } diff --git a/core/java/android/content/pm/dex/ArtManager.java b/core/java/android/content/pm/dex/ArtManager.java new file mode 100644 index 000000000000..201cd8d32cc1 --- /dev/null +++ b/core/java/android/content/pm/dex/ArtManager.java @@ -0,0 +1,156 @@ +/** + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm.dex; + +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Slog; + +/** + * Class for retrieving various kinds of information related to the runtime artifacts of + * packages that are currently installed on the device. + * + * @hide + */ +@SystemApi +public class ArtManager { + private static final String TAG = "ArtManager"; + + /** The snapshot failed because the package was not found. */ + public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; + /** The snapshot failed because the package code path does not exist. */ + public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; + /** The snapshot failed because of an internal error (e.g. error during opening profiles). */ + public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; + + private IArtManager mArtManager; + + /** + * @hide + */ + public ArtManager(@NonNull IArtManager manager) { + mArtManager = manager; + } + + /** + * 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. + * + * 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}. + * + * @param packageName the target package name + * @param codePath the code path for which the profile should be retrieved + * @param callback the callback which should be used for the result + * @param handler the handler 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) { + Slog.d(TAG, "Requesting profile snapshot for " + packageName + ":" + codePath); + + SnapshotRuntimeProfileCallbackDelegate delegate = + new SnapshotRuntimeProfileCallbackDelegate(callback, handler.getLooper()); + try { + mArtManager.snapshotRuntimeProfile(packageName, codePath, delegate); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Returns true if runtime profiles are enabled, false otherwise. + * + * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. + */ + @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES) + public boolean isRuntimeProfilingEnabled() { + try { + return mArtManager.isRuntimeProfilingEnabled(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + return false; + } + + /** + * Callback used for retrieving runtime profiles. + */ + public abstract static class SnapshotRuntimeProfileCallback { + /** + * Called when the profile snapshot finished with success. + * + * @param profileReadFd the file descriptor that can be used to read the profile. Note that + * the file might be empty (which is valid profile). + */ + public abstract void onSuccess(ParcelFileDescriptor profileReadFd); + + /** + * Called when the profile snapshot finished with an error. + * + * @param errCode the error code {@see SNAPSHOT_FAILED_PACKAGE_NOT_FOUND, + * SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND, SNAPSHOT_FAILED_INTERNAL_ERROR}. + */ + public abstract void onError(int errCode); + } + + 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; + private final ArtManager.SnapshotRuntimeProfileCallback mCallback; + private final Handler mHandler; + + private SnapshotRuntimeProfileCallbackDelegate( + ArtManager.SnapshotRuntimeProfileCallback callback, Looper looper) { + mCallback = callback; + mHandler = new Handler(looper, this); + } + + @Override + public void onSuccess(ParcelFileDescriptor profileReadFd) { + mHandler.obtainMessage(MSG_SNAPSHOT_OK, profileReadFd).sendToTarget(); + } + + @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; + } + } +} diff --git a/core/java/android/content/pm/dex/IArtManager.aidl b/core/java/android/content/pm/dex/IArtManager.aidl new file mode 100644 index 000000000000..8cbb452344b2 --- /dev/null +++ b/core/java/android/content/pm/dex/IArtManager.aidl @@ -0,0 +1,44 @@ +/* +** Copyright 2017, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.pm.dex; + +import android.content.pm.dex.ISnapshotRuntimeProfileCallback; + +/** + * A system service that provides access to runtime and compiler artifacts. + * + * @hide + */ +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. + * + * 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. + * + * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. + */ + boolean isRuntimeProfilingEnabled(); +} diff --git a/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl b/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl new file mode 100644 index 000000000000..3b4838fc7824 --- /dev/null +++ b/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl @@ -0,0 +1,29 @@ +/* +** Copyright 2017, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.content.pm.dex; + +import android.os.ParcelFileDescriptor; + +/** + * Callback used to post the result of a profile-snapshot operation. + * + * @hide + */ +oneway interface ISnapshotRuntimeProfileCallback { + void onSuccess(in ParcelFileDescriptor profileReadFd); + void onError(int errCode); +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index d9fb230f2176..09204261811d 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3616,6 +3616,11 @@ <permission android:name="android.permission.ACCESS_SHORTCUTS" android:protectionLevel="signature" /> + <!-- @SystemApi Allows an application to read the runtime profiles of other apps. + @hide <p>Not for use by third-party applications. --> + <permission android:name="android.permission.READ_RUNTIME_PROFILES" + android:protectionLevel="signature|privileged" /> + <application android:process="system" android:persistent="true" android:hasCode="false" diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4b6589c99df9..440ab13e410c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -111,7 +111,6 @@ import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures; import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE; import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS; import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; -import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter; import android.Manifest; import android.annotation.IntDef; @@ -187,6 +186,7 @@ import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; import android.content.pm.VersionedPackage; +import android.content.pm.dex.IArtManager; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; @@ -265,14 +265,12 @@ import com.android.internal.content.PackageHelper; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.IParcelFileDescriptorFactory; -import com.android.internal.os.RoSystemProperties; import com.android.internal.os.SomeArgs; import com.android.internal.os.Zygote; import com.android.internal.telephony.CarrierAppUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.DumpUtils; -import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; @@ -292,6 +290,7 @@ import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.Settings.DatabaseVersion; import com.android.server.pm.Settings.VersionInfo; +import com.android.server.pm.dex.ArtManagerService; import com.android.server.pm.dex.DexLogger; import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; @@ -307,30 +306,23 @@ import com.android.server.pm.permission.PermissionsState.PermissionState; import com.android.server.storage.DeviceStorageMonitorInternal; import dalvik.system.CloseGuard; -import dalvik.system.DexFile; import dalvik.system.VMRuntime; import libcore.io.IoUtils; -import libcore.io.Streams; -import libcore.util.EmptyArray; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.BufferedOutputStream; -import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -341,15 +333,12 @@ import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.SecureRandom; import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -363,7 +352,6 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.zip.GZIPInputStream; /** * Keep track of all those APKs everywhere. @@ -939,6 +927,8 @@ public class PackageManagerService extends IPackageManager.Stub final PackageInstallerService mInstallerService; + final ArtManagerService mArtManagerService; + private final PackageDexOptimizer mPackageDexOptimizer; // DexManager handles the usage of dex files (e.g. secondary files, whether or not a package // is used by other apps). @@ -3047,6 +3037,7 @@ public class PackageManagerService extends IPackageManager.Stub } mInstallerService = new PackageInstallerService(context, this); + mArtManagerService = new ArtManagerService(this); final Pair<ComponentName, String> instantAppResolverComponent = getInstantAppResolverLPr(); if (instantAppResolverComponent != null) { @@ -22273,6 +22264,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); return mInstallerService; } + @Override + public IArtManager getArtManager() { + return mArtManagerService; + } + private boolean userNeedsBadging(int userId) { int index = mUserNeedsBadging.indexOfKey(userId); if (index < 0) { diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java new file mode 100644 index 000000000000..5a1f840e945b --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.pm.dex; + +import android.Manifest; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.dex.ArtManager; +import android.os.Binder; +import android.os.Handler; +import android.os.RemoteException; +import android.content.pm.IPackageManager; +import android.content.pm.dex.ISnapshotRuntimeProfileCallback; +import android.os.SystemProperties; +import android.util.Slog; + +import com.android.internal.os.BackgroundThread; +import com.android.internal.util.Preconditions; + +/** + * A system service that provides access to runtime and compiler artifacts. + * + * This service is not accessed by users directly, instead one uses an instance of + * {@link ArtManager}, which can be accessed via {@link PackageManager} as follows: + * <p/> + * {@code context().getPackageManager().getArtManager();} + * <p class="note"> + * Note: Accessing runtime artifacts may require extra permissions. For example querying the + * runtime profiles of apps requires {@link android.Manifest.permission#READ_RUNTIME_PROFILES} + * which is a system-level permission that will not be granted to normal apps. + */ +public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { + private static final String TAG = "ArtManagerService"; + + private static boolean DEBUG = false; + private static boolean DEBUG_IGNORE_PERMISSIONS = false; + + private final IPackageManager mPackageManager; + private final Handler mHandler; + + public ArtManagerService(IPackageManager pm) { + mPackageManager = pm; + mHandler = new Handler(BackgroundThread.getHandler().getLooper()); + } + + @Override + public void snapshotRuntimeProfile(String packageName, String codePath, + 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(); + + if (DEBUG) { + Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath); + } + + PackageInfo info = null; + try { + // Note that we use the default user 0 to retrieve the package info. + // This doesn't really matter because for user 0 we always get a package back (even if + // it's not installed for the user 0). It is ok because we only care about the code + // paths and not if the package is enabled or not for the user. + + // TODO(calin): consider adding an API to PMS which can retrieve the + // PackageParser.Package. + info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0); + } catch (RemoteException ignored) { + // Should not happen. + } + if (info == null) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_PACKAGE_NOT_FOUND); + return; + } + + boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath); + String[] splitCodePaths = info.applicationInfo.getSplitCodePaths(); + if (!pathFound && (splitCodePaths != null)) { + for (String path : splitCodePaths) { + if (path.equals(codePath)) { + pathFound = true; + break; + } + } + } + if (!pathFound) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND); + return; + } + + // All good, move forward and get the profile. + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + } + + @Override + public boolean isRuntimeProfilingEnabled() { + // Verify that the caller has the right permissions. + checkReadRuntimeProfilePermission(); + + return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); + } + + /** + * Post {@link ISnapshotRuntimeProfileCallback#onError(int)} with the given error message + * on the internal {@code mHandler}. + */ + private void postError(ISnapshotRuntimeProfileCallback callback, String packageName, + int errCode) { + mHandler.post(() -> { + try { + callback.onError(errCode); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to callback after profile snapshot for " + packageName, e); + } + }); + } + + /** + * Verify that the binder calling uid has {@code android.permission.READ_RUNTIME_PROFILE}. + * If not, it throws a {@link SecurityException}. + */ + private void checkReadRuntimeProfilePermission() { + if (DEBUG_IGNORE_PERMISSIONS) { + return; + } + try { + int result = mPackageManager.checkUidPermission( + Manifest.permission.READ_RUNTIME_PROFILES, Binder.getCallingUid()); + if (result != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need " + + Manifest.permission.READ_RUNTIME_PROFILES + + " permission to snapshot profiles."); + } + } catch (RemoteException e) { + // Should not happen. + } + } +} diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java index 0c562e65bc85..ce8019f85632 100644 --- a/test-mock/src/android/test/mock/MockPackageManager.java +++ b/test-mock/src/android/test/mock/MockPackageManager.java @@ -46,6 +46,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; +import android.content.pm.dex.ArtManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Rect; @@ -1174,4 +1175,12 @@ public class MockPackageManager extends PackageManager { @Nullable DexModuleRegisterCallback callback) { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + @Override + public ArtManager getArtManager() { + throw new UnsupportedOperationException(); + } } |