Add SystemApis to expose runtime profile information

The API allows a system apps which acquired
{@code android.permission.READ_RUNTIME_PROFILE} to snapshot the runtime
profiles of installed packages.

The API is implemented in a new service class (AndroidRuntimeManager)
accessible from the context using
context().getPackageManager().getAndroidRuntimeManager().

The main functionality is exposed as a one way call into the
AndroidRuntimeManager with the result being posted on a callback. The
profile is available to the caller as a read-only ParcelFileDescriptor.

This CL only adds the API interfaces and validation. It does not fully
implement the functionality.

oneway void snapshotRuntimeProfile(in String packageName,
  in String codePath, in ISnapshotRuntimeProfileCallback callback)

Bug: 30934496
Test: gts-tradefed -m GtsAndroidRuntimeManagerHostTestCases

Change-Id: Iaa6be4715840f24508acba3162ea9c1ab725bd38
This commit is contained in:
Calin Juravle
2017-11-07 18:49:43 -08:00
parent 71e9a56fc3
commit 45f8b29ce0
12 changed files with 461 additions and 14 deletions

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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;
}
}
}

View File

@@ -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();
}

View File

@@ -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");
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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"

View File

@@ -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) {

View File

@@ -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.
}
}
}

View File

@@ -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();
}
}