ArtManagerService.java revision 1d875ad3ae5bb27016f9650b5bf4c39c08b6570e
1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package com.android.server.pm.dex; 18 19import android.Manifest; 20import android.content.pm.PackageInfo; 21import android.content.pm.PackageManager; 22import android.content.pm.dex.ArtManager; 23import android.os.Binder; 24import android.os.Handler; 25import android.os.RemoteException; 26import android.content.pm.IPackageManager; 27import android.content.pm.dex.ISnapshotRuntimeProfileCallback; 28import android.os.SystemProperties; 29import android.util.Slog; 30 31import com.android.internal.os.BackgroundThread; 32import com.android.internal.util.Preconditions; 33 34/** 35 * A system service that provides access to runtime and compiler artifacts. 36 * 37 * This service is not accessed by users directly, instead one uses an instance of 38 * {@link ArtManager}, which can be accessed via {@link PackageManager} as follows: 39 * <p/> 40 * {@code context().getPackageManager().getArtManager();} 41 * <p class="note"> 42 * Note: Accessing runtime artifacts may require extra permissions. For example querying the 43 * runtime profiles of apps requires {@link android.Manifest.permission#READ_RUNTIME_PROFILES} 44 * which is a system-level permission that will not be granted to normal apps. 45 */ 46public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { 47 private static final String TAG = "ArtManagerService"; 48 49 private static boolean DEBUG = false; 50 private static boolean DEBUG_IGNORE_PERMISSIONS = false; 51 52 private final IPackageManager mPackageManager; 53 private final Handler mHandler; 54 55 public ArtManagerService(IPackageManager pm) { 56 mPackageManager = pm; 57 mHandler = new Handler(BackgroundThread.getHandler().getLooper()); 58 } 59 60 @Override 61 public void snapshotRuntimeProfile(String packageName, String codePath, 62 ISnapshotRuntimeProfileCallback callback) { 63 // Sanity checks on the arguments. 64 Preconditions.checkStringNotEmpty(packageName); 65 Preconditions.checkStringNotEmpty(codePath); 66 Preconditions.checkNotNull(callback); 67 68 // Verify that the caller has the right permissions. 69 checkReadRuntimeProfilePermission(); 70 71 if (DEBUG) { 72 Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath); 73 } 74 75 PackageInfo info = null; 76 try { 77 // Note that we use the default user 0 to retrieve the package info. 78 // This doesn't really matter because for user 0 we always get a package back (even if 79 // it's not installed for the user 0). It is ok because we only care about the code 80 // paths and not if the package is enabled or not for the user. 81 82 // TODO(calin): consider adding an API to PMS which can retrieve the 83 // PackageParser.Package. 84 info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0); 85 } catch (RemoteException ignored) { 86 // Should not happen. 87 } 88 if (info == null) { 89 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_PACKAGE_NOT_FOUND); 90 return; 91 } 92 93 boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath); 94 String[] splitCodePaths = info.applicationInfo.getSplitCodePaths(); 95 if (!pathFound && (splitCodePaths != null)) { 96 for (String path : splitCodePaths) { 97 if (path.equals(codePath)) { 98 pathFound = true; 99 break; 100 } 101 } 102 } 103 if (!pathFound) { 104 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND); 105 return; 106 } 107 108 // All good, move forward and get the profile. 109 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); 110 } 111 112 @Override 113 public boolean isRuntimeProfilingEnabled() { 114 // Verify that the caller has the right permissions. 115 checkReadRuntimeProfilePermission(); 116 117 return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); 118 } 119 120 /** 121 * Post {@link ISnapshotRuntimeProfileCallback#onError(int)} with the given error message 122 * on the internal {@code mHandler}. 123 */ 124 private void postError(ISnapshotRuntimeProfileCallback callback, String packageName, 125 int errCode) { 126 mHandler.post(() -> { 127 try { 128 callback.onError(errCode); 129 } catch (RemoteException e) { 130 Slog.w(TAG, "Failed to callback after profile snapshot for " + packageName, e); 131 } 132 }); 133 } 134 135 /** 136 * Verify that the binder calling uid has {@code android.permission.READ_RUNTIME_PROFILE}. 137 * If not, it throws a {@link SecurityException}. 138 */ 139 private void checkReadRuntimeProfilePermission() { 140 if (DEBUG_IGNORE_PERMISSIONS) { 141 return; 142 } 143 try { 144 int result = mPackageManager.checkUidPermission( 145 Manifest.permission.READ_RUNTIME_PROFILES, Binder.getCallingUid()); 146 if (result != PackageManager.PERMISSION_GRANTED) { 147 throw new SecurityException("You need " 148 + Manifest.permission.READ_RUNTIME_PROFILES 149 + " permission to snapshot profiles."); 150 } 151 } catch (RemoteException e) { 152 // Should not happen. 153 } 154 } 155} 156