blob: 21daa39e05e04b666e9941d200c1a4e190f2281e [file] [log] [blame]
Calin Juravle45f8b292017-11-07 18:49:43 -08001/*
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
Calin Juravle3621be72018-01-18 15:17:29 -080019import android.annotation.UserIdInt;
Jeff Sharkey0ad62832018-04-19 11:20:57 -060020import android.app.AppOpsManager;
21import android.content.Context;
Calin Juravle3621be72018-01-18 15:17:29 -080022import android.content.pm.ApplicationInfo;
Calin Juravle759fbda2018-02-20 19:52:30 +000023import android.content.pm.IPackageManager;
Calin Juravle45f8b292017-11-07 18:49:43 -080024import android.content.pm.PackageInfo;
25import android.content.pm.PackageManager;
Calin Juravle3621be72018-01-18 15:17:29 -080026import android.content.pm.PackageParser;
Calin Juravle45f8b292017-11-07 18:49:43 -080027import android.content.pm.dex.ArtManager;
Calin Juravlefcbb74a2018-01-21 21:39:18 -080028import android.content.pm.dex.ArtManager.ProfileType;
Calin Juravle759fbda2018-02-20 19:52:30 +000029import android.content.pm.dex.ArtManagerInternal;
Calin Juravle3621be72018-01-18 15:17:29 -080030import android.content.pm.dex.DexMetadataHelper;
Calin Juravlea86783b2018-03-21 14:25:59 -070031import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
Calin Juravle759fbda2018-02-20 19:52:30 +000032import android.content.pm.dex.PackageOptimizationInfo;
Calin Juravle45f8b292017-11-07 18:49:43 -080033import android.os.Binder;
Calin Juravlefcbb74a2018-01-21 21:39:18 -080034import android.os.Build;
Calin Juravle45f8b292017-11-07 18:49:43 -080035import android.os.Handler;
Calin Juravlefd9f8ae2017-11-29 18:26:55 -080036import android.os.ParcelFileDescriptor;
Calin Juravle4d6f5812018-04-27 17:47:24 -070037import android.os.Process;
Calin Juravle45f8b292017-11-07 18:49:43 -080038import android.os.RemoteException;
Calin Juravle45f8b292017-11-07 18:49:43 -080039import android.os.SystemProperties;
Calin Juravlefd9f8ae2017-11-29 18:26:55 -080040import android.os.UserHandle;
Calin Juravlefcbb74a2018-01-21 21:39:18 -080041import android.system.Os;
Calin Juravle3621be72018-01-18 15:17:29 -080042import android.util.ArrayMap;
Jeff Sharkey0ad62832018-04-19 11:20:57 -060043import android.util.Log;
Calin Juravle45f8b292017-11-07 18:49:43 -080044import android.util.Slog;
Jeff Sharkey0ad62832018-04-19 11:20:57 -060045
Calin Juravlefd9f8ae2017-11-29 18:26:55 -080046import com.android.internal.annotations.GuardedBy;
Calin Juravle45f8b292017-11-07 18:49:43 -080047import com.android.internal.os.BackgroundThread;
Calin Juravle4d6f5812018-04-27 17:47:24 -070048import com.android.internal.os.RoSystemProperties;
Calin Juravle3621be72018-01-18 15:17:29 -080049import com.android.internal.util.ArrayUtils;
Calin Juravle45f8b292017-11-07 18:49:43 -080050import com.android.internal.util.Preconditions;
Calin Juravle759fbda2018-02-20 19:52:30 +000051import com.android.server.LocalServices;
Calin Juravlefd9f8ae2017-11-29 18:26:55 -080052import com.android.server.pm.Installer;
53import com.android.server.pm.Installer.InstallerException;
Calin Juravlea86783b2018-03-21 14:25:59 -070054import com.android.server.pm.PackageManagerServiceCompilerMapping;
Jeff Sharkey0ad62832018-04-19 11:20:57 -060055
Calin Juravle759fbda2018-02-20 19:52:30 +000056import dalvik.system.DexFile;
Calin Juravle759fbda2018-02-20 19:52:30 +000057import dalvik.system.VMRuntime;
Jeff Sharkey0ad62832018-04-19 11:20:57 -060058
Calin Juravlefcbb74a2018-01-21 21:39:18 -080059import libcore.io.IoUtils;
60import libcore.util.NonNull;
61import libcore.util.Nullable;
Calin Juravle45f8b292017-11-07 18:49:43 -080062
Jeff Sharkey0ad62832018-04-19 11:20:57 -060063import java.io.File;
64import java.io.FileNotFoundException;
65
Calin Juravle45f8b292017-11-07 18:49:43 -080066/**
67 * A system service that provides access to runtime and compiler artifacts.
68 *
69 * This service is not accessed by users directly, instead one uses an instance of
70 * {@link ArtManager}, which can be accessed via {@link PackageManager} as follows:
71 * <p/>
72 * {@code context().getPackageManager().getArtManager();}
73 * <p class="note">
74 * Note: Accessing runtime artifacts may require extra permissions. For example querying the
75 * runtime profiles of apps requires {@link android.Manifest.permission#READ_RUNTIME_PROFILES}
76 * which is a system-level permission that will not be granted to normal apps.
77 */
78public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
79 private static final String TAG = "ArtManagerService";
Jeff Sharkey0ad62832018-04-19 11:20:57 -060080 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Calin Juravle45f8b292017-11-07 18:49:43 -080081
Calin Juravlefcbb74a2018-01-21 21:39:18 -080082 // Package name used to create the profile directory layout when
83 // taking a snapshot of the boot image profile.
84 private static final String BOOT_IMAGE_ANDROID_PACKAGE = "android";
85 // Profile name used for the boot image profile.
86 private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof";
87
Jeff Sharkey0ad62832018-04-19 11:20:57 -060088 private final Context mContext;
Calin Juravle45f8b292017-11-07 18:49:43 -080089 private final IPackageManager mPackageManager;
Calin Juravlefd9f8ae2017-11-29 18:26:55 -080090 private final Object mInstallLock;
91 @GuardedBy("mInstallLock")
92 private final Installer mInstaller;
93
Calin Juravle45f8b292017-11-07 18:49:43 -080094 private final Handler mHandler;
95
Calin Juravlea86783b2018-03-21 14:25:59 -070096 static {
97 verifyTronLoggingConstants();
98 }
99
Jeff Sharkey0ad62832018-04-19 11:20:57 -0600100 public ArtManagerService(Context context, IPackageManager pm, Installer installer,
101 Object installLock) {
102 mContext = context;
Calin Juravle45f8b292017-11-07 18:49:43 -0800103 mPackageManager = pm;
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800104 mInstaller = installer;
105 mInstallLock = installLock;
Calin Juravle45f8b292017-11-07 18:49:43 -0800106 mHandler = new Handler(BackgroundThread.getHandler().getLooper());
Calin Juravle759fbda2018-02-20 19:52:30 +0000107
108 LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl());
Calin Juravle45f8b292017-11-07 18:49:43 -0800109 }
110
Calin Juravle4d6f5812018-04-27 17:47:24 -0700111 private boolean checkAndroidPermissions(int callingUid, String callingPackage) {
Jeff Sharkey0ad62832018-04-19 11:20:57 -0600112 // Callers always need this permission
113 mContext.enforceCallingOrSelfPermission(
114 android.Manifest.permission.READ_RUNTIME_PROFILES, TAG);
115
116 // Callers also need the ability to read usage statistics
117 switch (mContext.getSystemService(AppOpsManager.class)
118 .noteOp(AppOpsManager.OP_GET_USAGE_STATS, callingUid, callingPackage)) {
119 case AppOpsManager.MODE_ALLOWED:
120 return true;
121 case AppOpsManager.MODE_DEFAULT:
122 mContext.enforceCallingOrSelfPermission(
123 android.Manifest.permission.PACKAGE_USAGE_STATS, TAG);
124 return true;
125 default:
126 return false;
127 }
128 }
129
Calin Juravle4d6f5812018-04-27 17:47:24 -0700130 /**
131 * Checks if the calling user is the shell user and if it is, it checks if it can
132 * to take a profile snapshot of the give package:
133 * - on debuggable builds the shell user can take profile snapshots of any app.
134 * - on non-debuggable builds the shell user can only take snapshots of debuggable apps.
135 *
136 * Returns true iff the callingUid is the shell uid and the shell is allowed snapshot profiles.
137 *
138 * Note that the root users will go through the regular {@link #checkAndroidPermissions) checks.
139 */
140 private boolean checkShellPermissions(@ProfileType int profileType, String packageName,
141 int callingUid) {
142 if (callingUid != Process.SHELL_UID) {
143 return false;
144 }
145 if (RoSystemProperties.DEBUGGABLE) {
146 return true;
147 }
148 if (profileType == ArtManager.PROFILE_BOOT_IMAGE) {
149 // The shell cannot profile the boot image on non-debuggable builds.
150 return false;
151 }
152 PackageInfo info = null;
153 try {
154 info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
155 } catch (RemoteException ignored) {
156 // Should not happen.
157 }
158 if (info == null) {
159 return false;
160 }
161
162 // On user builds the shell can only profile debuggable apps.
163 return (info.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE)
164 == ApplicationInfo.FLAG_DEBUGGABLE;
165 }
166
167
Calin Juravle45f8b292017-11-07 18:49:43 -0800168 @Override
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800169 public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
Jeff Sharkey0ad62832018-04-19 11:20:57 -0600170 @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback,
171 String callingPackage) {
Calin Juravle4d6f5812018-04-27 17:47:24 -0700172 int callingUid = Binder.getCallingUid();
173 if (!checkShellPermissions(profileType, packageName, callingUid) &&
174 !checkAndroidPermissions(callingUid, callingPackage)) {
Jeff Sharkey0ad62832018-04-19 11:20:57 -0600175 try {
176 callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
177 } catch (RemoteException ignored) {
178 }
179 return;
180 }
181
Calin Juravle45f8b292017-11-07 18:49:43 -0800182 // Sanity checks on the arguments.
Calin Juravle45f8b292017-11-07 18:49:43 -0800183 Preconditions.checkNotNull(callback);
184
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800185 boolean bootImageProfile = profileType == ArtManager.PROFILE_BOOT_IMAGE;
186 if (!bootImageProfile) {
187 Preconditions.checkStringNotEmpty(codePath);
188 Preconditions.checkStringNotEmpty(packageName);
189 }
190
Jeff Sharkey0ad62832018-04-19 11:20:57 -0600191 // Verify that runtime profiling is enabled.
192 if (!isRuntimeProfilingEnabled(profileType, callingPackage)) {
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800193 throw new IllegalStateException("Runtime profiling is not enabled for " + profileType);
194 }
Calin Juravle45f8b292017-11-07 18:49:43 -0800195
196 if (DEBUG) {
197 Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath);
198 }
199
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800200 if (bootImageProfile) {
201 snapshotBootImageProfile(callback);
202 } else {
203 snapshotAppProfile(packageName, codePath, callback);
204 }
205 }
206
207 private void snapshotAppProfile(String packageName, String codePath,
208 ISnapshotRuntimeProfileCallback callback) {
Calin Juravle45f8b292017-11-07 18:49:43 -0800209 PackageInfo info = null;
210 try {
211 // Note that we use the default user 0 to retrieve the package info.
212 // This doesn't really matter because for user 0 we always get a package back (even if
213 // it's not installed for the user 0). It is ok because we only care about the code
214 // paths and not if the package is enabled or not for the user.
215
216 // TODO(calin): consider adding an API to PMS which can retrieve the
217 // PackageParser.Package.
218 info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
219 } catch (RemoteException ignored) {
220 // Should not happen.
221 }
222 if (info == null) {
223 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_PACKAGE_NOT_FOUND);
224 return;
225 }
226
227 boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath);
Calin Juravle6ae39fc2018-01-19 20:32:47 -0800228 String splitName = null;
Calin Juravle45f8b292017-11-07 18:49:43 -0800229 String[] splitCodePaths = info.applicationInfo.getSplitCodePaths();
230 if (!pathFound && (splitCodePaths != null)) {
Calin Juravle6ae39fc2018-01-19 20:32:47 -0800231 for (int i = splitCodePaths.length - 1; i >= 0; i--) {
232 if (splitCodePaths[i].equals(codePath)) {
Calin Juravle45f8b292017-11-07 18:49:43 -0800233 pathFound = true;
Calin Juravle6ae39fc2018-01-19 20:32:47 -0800234 splitName = info.applicationInfo.splitNames[i];
Calin Juravle45f8b292017-11-07 18:49:43 -0800235 break;
236 }
237 }
238 }
239 if (!pathFound) {
240 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND);
241 return;
242 }
243
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800244 // All good, create the profile snapshot.
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800245 int appId = UserHandle.getAppId(info.applicationInfo.uid);
246 if (appId < 0) {
247 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
248 Slog.wtf(TAG, "AppId is -1 for package: " + packageName);
249 return;
250 }
251
252 createProfileSnapshot(packageName, ArtManager.getProfileName(splitName), codePath,
253 appId, callback);
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800254 // Destroy the snapshot, we no longer need it.
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800255 destroyProfileSnapshot(packageName, ArtManager.getProfileName(splitName));
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800256 }
257
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800258 private void createProfileSnapshot(String packageName, String profileName, String classpath,
259 int appId, ISnapshotRuntimeProfileCallback callback) {
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800260 // Ask the installer to snapshot the profile.
261 synchronized (mInstallLock) {
262 try {
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800263 if (!mInstaller.createProfileSnapshot(appId, packageName, profileName, classpath)) {
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800264 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
265 return;
266 }
267 } catch (InstallerException e) {
268 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
269 return;
270 }
271 }
272
273 // Open the snapshot and invoke the callback.
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800274 File snapshotProfile = ArtManager.getProfileSnapshotFileForName(packageName, profileName);
275
276 ParcelFileDescriptor fd = null;
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800277 try {
278 fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY);
Calin Juravle82d55a22018-03-20 16:45:08 -0700279 if (fd == null || !fd.getFileDescriptor().valid()) {
280 Slog.wtf(TAG,
281 "ParcelFileDescriptor.open returned an invalid descriptor for "
282 + packageName + ":" + snapshotProfile + ". isNull=" + (fd == null));
283 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
284 } else {
285 postSuccess(packageName, fd, callback);
286 }
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800287 } catch (FileNotFoundException e) {
Calin Juravle6ae39fc2018-01-19 20:32:47 -0800288 Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":"
289 + snapshotProfile, e);
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800290 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
291 }
292 }
293
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800294 private void destroyProfileSnapshot(String packageName, String profileName) {
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800295 if (DEBUG) {
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800296 Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + profileName);
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800297 }
298
299 synchronized (mInstallLock) {
300 try {
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800301 mInstaller.destroyProfileSnapshot(packageName, profileName);
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800302 } catch (InstallerException e) {
303 Slog.e(TAG, "Failed to destroy profile snapshot for " +
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800304 packageName + ":" + profileName, e);
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800305 }
306 }
Calin Juravle45f8b292017-11-07 18:49:43 -0800307 }
308
309 @Override
Jeff Sharkey0ad62832018-04-19 11:20:57 -0600310 public boolean isRuntimeProfilingEnabled(@ProfileType int profileType, String callingPackage) {
Calin Juravle4d6f5812018-04-27 17:47:24 -0700311 int callingUid = Binder.getCallingUid();
312 if (callingUid != Process.SHELL_UID && !checkAndroidPermissions(callingUid, callingPackage)) {
Jeff Sharkey0ad62832018-04-19 11:20:57 -0600313 return false;
314 }
Calin Juravle45f8b292017-11-07 18:49:43 -0800315
Calin Juravlefcbb74a2018-01-21 21:39:18 -0800316 switch (profileType) {
317 case ArtManager.PROFILE_APPS :
318 return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
319 case ArtManager.PROFILE_BOOT_IMAGE:
320 return (Build.IS_USERDEBUG || Build.IS_ENG) &&
321 SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false) &&
322 SystemProperties.getBoolean("dalvik.vm.profilebootimage", false);
323 default:
324 throw new IllegalArgumentException("Invalid profile type:" + profileType);
325 }
326 }
327
328 private void snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback) {
329 // Combine the profiles for boot classpath and system server classpath.
330 // This avoids having yet another type of profiles and simplifies the processing.
331 String classpath = String.join(":", Os.getenv("BOOTCLASSPATH"),
332 Os.getenv("SYSTEMSERVERCLASSPATH"));
333
334 // Create the snapshot.
335 createProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME, classpath,
336 /*appId*/ -1, callback);
337 // Destroy the snapshot, we no longer need it.
338 destroyProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME);
Calin Juravle45f8b292017-11-07 18:49:43 -0800339 }
340
341 /**
342 * Post {@link ISnapshotRuntimeProfileCallback#onError(int)} with the given error message
343 * on the internal {@code mHandler}.
344 */
345 private void postError(ISnapshotRuntimeProfileCallback callback, String packageName,
346 int errCode) {
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800347 if (DEBUG) {
348 Slog.d(TAG, "Failed to snapshot profile for " + packageName + " with error: " +
349 errCode);
350 }
Calin Juravle45f8b292017-11-07 18:49:43 -0800351 mHandler.post(() -> {
352 try {
353 callback.onError(errCode);
Calin Juravle82d55a22018-03-20 16:45:08 -0700354 } catch (Exception e) {
Calin Juravle45f8b292017-11-07 18:49:43 -0800355 Slog.w(TAG, "Failed to callback after profile snapshot for " + packageName, e);
356 }
357 });
358 }
359
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800360 private void postSuccess(String packageName, ParcelFileDescriptor fd,
361 ISnapshotRuntimeProfileCallback callback) {
362 if (DEBUG) {
363 Slog.d(TAG, "Successfully snapshot profile for " + packageName);
364 }
365 mHandler.post(() -> {
366 try {
Calin Juravle82d55a22018-03-20 16:45:08 -0700367 // Double check that the descriptor is still valid.
368 // We've seen production issues (b/76028139) where this can turn invalid (there are
369 // suspicions around the finalizer behaviour).
370 if (fd.getFileDescriptor().valid()) {
371 callback.onSuccess(fd);
372 } else {
373 Slog.wtf(TAG, "The snapshot FD became invalid before posting the result for "
374 + packageName);
375 callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
376 }
377 } catch (Exception e) {
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800378 Slog.w(TAG,
379 "Failed to call onSuccess after profile snapshot for " + packageName, e);
Calin Juravle2b3c1352018-03-01 19:42:45 -0800380 } finally {
381 IoUtils.closeQuietly(fd);
Calin Juravlefd9f8ae2017-11-29 18:26:55 -0800382 }
383 });
384 }
385
Calin Juravle45f8b292017-11-07 18:49:43 -0800386 /**
Calin Juravle3621be72018-01-18 15:17:29 -0800387 * Prepare the application profiles.
388 * For all code paths:
389 * - create the current primary profile to save time at app startup time.
390 * - copy the profiles from the associated dex metadata file to the reference profile.
391 */
392 public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user) {
393 final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
Calin Juravle5bbe26e2018-01-24 14:43:24 -0800394 if (user < 0) {
395 Slog.wtf(TAG, "Invalid user id: " + user);
396 return;
397 }
398 if (appId < 0) {
399 Slog.wtf(TAG, "Invalid app id: " + appId);
400 return;
401 }
Calin Juravle3621be72018-01-18 15:17:29 -0800402 try {
403 ArrayMap<String, String> codePathsProfileNames = getPackageProfileNames(pkg);
404 for (int i = codePathsProfileNames.size() - 1; i >= 0; i--) {
405 String codePath = codePathsProfileNames.keyAt(i);
406 String profileName = codePathsProfileNames.valueAt(i);
407 File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath));
408 String dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
409 synchronized (mInstaller) {
410 boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId,
411 profileName, codePath, dexMetadataPath);
412 if (!result) {
413 Slog.e(TAG, "Failed to prepare profile for " +
414 pkg.packageName + ":" + codePath);
415 }
416 }
417 }
418 } catch (InstallerException e) {
419 Slog.e(TAG, "Failed to prepare profile for " + pkg.packageName, e);
420 }
421 }
422
423 /**
Calin Juravle5bbe26e2018-01-24 14:43:24 -0800424 * Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}.
425 */
426 public void prepareAppProfiles(PackageParser.Package pkg, int[] user) {
427 for (int i = 0; i < user.length; i++) {
428 prepareAppProfiles(pkg, user[i]);
429 }
430 }
431
432 /**
Calin Juravle6ae39fc2018-01-19 20:32:47 -0800433 * Clear the profiles for the given package.
434 */
435 public void clearAppProfiles(PackageParser.Package pkg) {
436 try {
437 ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
438 for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
439 String profileName = packageProfileNames.valueAt(i);
440 mInstaller.clearAppProfiles(pkg.packageName, profileName);
441 }
442 } catch (InstallerException e) {
443 Slog.w(TAG, String.valueOf(e));
444 }
445 }
446
447 /**
448 * Dumps the profiles for the given package.
449 */
450 public void dumpProfiles(PackageParser.Package pkg) {
451 final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
452 try {
453 ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
454 for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
455 String codePath = packageProfileNames.keyAt(i);
456 String profileName = packageProfileNames.valueAt(i);
457 synchronized (mInstallLock) {
458 mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath);
459 }
460 }
461 } catch (InstallerException e) {
462 Slog.w(TAG, "Failed to dump profiles", e);
463 }
464 }
465
466 /**
Calin Juravle3621be72018-01-18 15:17:29 -0800467 * Build the profiles names for all the package code paths (excluding resource only paths).
468 * Return the map [code path -> profile name].
469 */
470 private ArrayMap<String, String> getPackageProfileNames(PackageParser.Package pkg) {
471 ArrayMap<String, String> result = new ArrayMap<>();
472 if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
473 result.put(pkg.baseCodePath, ArtManager.getProfileName(null));
474 }
475 if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
476 for (int i = 0; i < pkg.splitCodePaths.length; i++) {
477 if ((pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
478 result.put(pkg.splitCodePaths[i], ArtManager.getProfileName(pkg.splitNames[i]));
479 }
480 }
481 }
482 return result;
483 }
Calin Juravle759fbda2018-02-20 19:52:30 +0000484
Calin Juravlea86783b2018-03-21 14:25:59 -0700485 // Constants used for logging compilation filter to TRON.
486 // DO NOT CHANGE existing values.
487 //
488 // NOTE: '-1' value is reserved for the case where we cannot produce a valid
489 // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the
490 // ActivityMetricsLoggers.
491 private static final int TRON_COMPILATION_FILTER_ERROR = 0;
492 private static final int TRON_COMPILATION_FILTER_UNKNOWN = 1;
493 private static final int TRON_COMPILATION_FILTER_ASSUMED_VERIFIED = 2;
494 private static final int TRON_COMPILATION_FILTER_EXTRACT = 3;
495 private static final int TRON_COMPILATION_FILTER_VERIFY = 4;
496 private static final int TRON_COMPILATION_FILTER_QUICKEN = 5;
497 private static final int TRON_COMPILATION_FILTER_SPACE_PROFILE = 6;
498 private static final int TRON_COMPILATION_FILTER_SPACE = 7;
499 private static final int TRON_COMPILATION_FILTER_SPEED_PROFILE = 8;
500 private static final int TRON_COMPILATION_FILTER_SPEED = 9;
501 private static final int TRON_COMPILATION_FILTER_EVERYTHING_PROFILE = 10;
502 private static final int TRON_COMPILATION_FILTER_EVERYTHING = 11;
503 private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK = 12;
504 private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK = 13;
505 private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK = 14;
506
507 // Constants used for logging compilation reason to TRON.
508 // DO NOT CHANGE existing values.
509 //
510 // NOTE: '-1' value is reserved for the case where we cannot produce a valid
511 // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the
512 // ActivityMetricsLoggers.
513 private static final int TRON_COMPILATION_REASON_ERROR = 0;
514 private static final int TRON_COMPILATION_REASON_UNKNOWN = 1;
515 private static final int TRON_COMPILATION_REASON_FIRST_BOOT = 2;
516 private static final int TRON_COMPILATION_REASON_BOOT = 3;
517 private static final int TRON_COMPILATION_REASON_INSTALL = 4;
518 private static final int TRON_COMPILATION_REASON_BG_DEXOPT = 5;
519 private static final int TRON_COMPILATION_REASON_AB_OTA = 6;
520 private static final int TRON_COMPILATION_REASON_INACTIVE = 7;
521 private static final int TRON_COMPILATION_REASON_SHARED = 8;
Calin Juravle0610dd12018-07-20 15:51:17 -0700522 private static final int TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA = 9;
523
524 // The annotation to add as a suffix to the compilation reason when dexopt was
525 // performed with dex metadata.
526 public static final String DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION = "-dm";
Calin Juravlea86783b2018-03-21 14:25:59 -0700527
528 /**
529 * Convert the compilation reason to an int suitable to be logged to TRON.
530 */
531 private static int getCompilationReasonTronValue(String compilationReason) {
532 switch (compilationReason) {
533 case "unknown" : return TRON_COMPILATION_REASON_UNKNOWN;
534 case "error" : return TRON_COMPILATION_REASON_ERROR;
535 case "first-boot" : return TRON_COMPILATION_REASON_FIRST_BOOT;
536 case "boot" : return TRON_COMPILATION_REASON_BOOT;
537 case "install" : return TRON_COMPILATION_REASON_INSTALL;
538 case "bg-dexopt" : return TRON_COMPILATION_REASON_BG_DEXOPT;
539 case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA;
540 case "inactive" : return TRON_COMPILATION_REASON_INACTIVE;
541 case "shared" : return TRON_COMPILATION_REASON_SHARED;
Calin Juravle0610dd12018-07-20 15:51:17 -0700542 // This is a special marker for dex metadata installation that does not
543 // have an equivalent as a system property.
544 case "install" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
545 return TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA;
Calin Juravlea86783b2018-03-21 14:25:59 -0700546 default: return TRON_COMPILATION_REASON_UNKNOWN;
547 }
548 }
549
550 /**
551 * Convert the compilation filter to an int suitable to be logged to TRON.
552 */
553 private static int getCompilationFilterTronValue(String compilationFilter) {
554 switch (compilationFilter) {
555 case "error" : return TRON_COMPILATION_FILTER_ERROR;
556 case "unknown" : return TRON_COMPILATION_FILTER_UNKNOWN;
557 case "assume-verified" : return TRON_COMPILATION_FILTER_ASSUMED_VERIFIED;
558 case "extract" : return TRON_COMPILATION_FILTER_EXTRACT;
559 case "verify" : return TRON_COMPILATION_FILTER_VERIFY;
560 case "quicken" : return TRON_COMPILATION_FILTER_QUICKEN;
561 case "space-profile" : return TRON_COMPILATION_FILTER_SPACE_PROFILE;
562 case "space" : return TRON_COMPILATION_FILTER_SPACE;
563 case "speed-profile" : return TRON_COMPILATION_FILTER_SPEED_PROFILE;
564 case "speed" : return TRON_COMPILATION_FILTER_SPEED;
565 case "everything-profile" : return TRON_COMPILATION_FILTER_EVERYTHING_PROFILE;
566 case "everything" : return TRON_COMPILATION_FILTER_EVERYTHING;
567 case "run-from-apk" : return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK;
568 case "run-from-apk-fallback" :
569 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
570 case "run-from-vdex-fallback" :
571 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
572 default: return TRON_COMPILATION_FILTER_UNKNOWN;
573 }
574 }
575
576 private static void verifyTronLoggingConstants() {
577 for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
578 String reason = PackageManagerServiceCompilerMapping.REASON_STRINGS[i];
579 int value = getCompilationReasonTronValue(reason);
580 if (value == TRON_COMPILATION_REASON_ERROR
581 || value == TRON_COMPILATION_REASON_UNKNOWN) {
582 throw new IllegalArgumentException("Compilation reason not configured for TRON "
583 + "logging: " + reason);
584 }
585 }
586 }
587
Calin Juravle759fbda2018-02-20 19:52:30 +0000588 private class ArtManagerInternalImpl extends ArtManagerInternal {
589 @Override
590 public PackageOptimizationInfo getPackageOptimizationInfo(
591 ApplicationInfo info, String abi) {
592 String compilationReason;
593 String compilationFilter;
594 try {
595 String isa = VMRuntime.getInstructionSet(abi);
Calin Juravle7fc0f632018-03-30 12:38:59 -0700596 DexFile.OptimizationInfo optInfo =
597 DexFile.getDexFileOptimizationInfo(info.getBaseCodePath(), isa);
598 compilationFilter = optInfo.getStatus();
599 compilationReason = optInfo.getReason();
Calin Juravle759fbda2018-02-20 19:52:30 +0000600 } catch (FileNotFoundException e) {
601 Slog.e(TAG, "Could not get optimizations status for " + info.getBaseCodePath(), e);
602 compilationFilter = "error";
603 compilationReason = "error";
604 } catch (IllegalArgumentException e) {
605 Slog.wtf(TAG, "Requested optimization status for " + info.getBaseCodePath()
606 + " due to an invalid abi " + abi, e);
607 compilationFilter = "error";
608 compilationReason = "error";
609 }
610
Calin Juravlea86783b2018-03-21 14:25:59 -0700611 int compilationFilterTronValue = getCompilationFilterTronValue(compilationFilter);
612 int compilationReasonTronValue = getCompilationReasonTronValue(compilationReason);
613
614 return new PackageOptimizationInfo(
615 compilationFilterTronValue, compilationReasonTronValue);
Calin Juravle759fbda2018-02-20 19:52:30 +0000616 }
617 }
Calin Juravle45f8b292017-11-07 18:49:43 -0800618}