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 
17 package com.android.server.pm.dex;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.UserIdInt;
22 import android.app.AppOpsManager;
23 import android.content.Context;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.IPackageManager;
26 import android.content.pm.PackageInfo;
27 import android.content.pm.PackageManager;
28 import android.content.pm.dex.ArtManager;
29 import android.content.pm.dex.ArtManager.ProfileType;
30 import android.content.pm.dex.ArtManagerInternal;
31 import android.content.pm.dex.DexMetadataHelper;
32 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
33 import android.content.pm.dex.PackageOptimizationInfo;
34 import android.os.Binder;
35 import android.os.Build;
36 import android.os.Handler;
37 import android.os.ParcelFileDescriptor;
38 import android.os.Process;
39 import android.os.RemoteException;
40 import android.os.ServiceManager;
41 import android.os.SystemProperties;
42 import android.os.UserHandle;
43 import android.system.Os;
44 import android.util.ArrayMap;
45 import android.util.Log;
46 import android.util.Slog;
47 
48 import com.android.internal.os.BackgroundThread;
49 import com.android.internal.os.RoSystemProperties;
50 import com.android.internal.util.ArrayUtils;
51 import com.android.internal.util.Preconditions;
52 import com.android.server.LocalServices;
53 import com.android.server.art.ArtManagerLocal;
54 import com.android.server.pm.DexOptHelper;
55 import com.android.server.pm.Installer;
56 import com.android.server.pm.Installer.InstallerException;
57 import com.android.server.pm.Installer.LegacyDexoptDisabledException;
58 import com.android.server.pm.PackageManagerLocal;
59 import com.android.server.pm.PackageManagerService;
60 import com.android.server.pm.PackageManagerServiceCompilerMapping;
61 import com.android.server.pm.PackageManagerServiceUtils;
62 import com.android.server.pm.parsing.PackageInfoUtils;
63 import com.android.server.pm.pkg.AndroidPackage;
64 import com.android.server.pm.pkg.PackageState;
65 
66 import dalvik.system.DexFile;
67 import dalvik.system.VMRuntime;
68 
69 import libcore.io.IoUtils;
70 
71 import java.io.File;
72 import java.io.FileNotFoundException;
73 import java.io.IOException;
74 import java.nio.file.Files;
75 import java.nio.file.Path;
76 import java.nio.file.Paths;
77 import java.util.Objects;
78 
79 /**
80  * A system service that provides access to runtime and compiler artifacts.
81  *
82  * This service is not accessed by users directly, instead one uses an instance of
83  * {@link ArtManager}, which can be accessed via {@link PackageManager} as follows:
84  * <p/>
85  * {@code context().getPackageManager().getArtManager();}
86  * <p class="note">
87  * Note: Accessing runtime artifacts may require extra permissions. For example querying the
88  * runtime profiles of apps requires {@link android.Manifest.permission#READ_RUNTIME_PROFILES}
89  * which is a system-level permission that will not be granted to normal apps.
90  */
91 public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
92     private static final String TAG = "ArtManagerService";
93     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
94 
95     // Package name used to create the profile directory layout when
96     // taking a snapshot of the boot image profile.
97     private static final String BOOT_IMAGE_ANDROID_PACKAGE = "android";
98     // Profile name used for the boot image profile.
99     private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof";
100 
101     private final Context mContext;
102     private IPackageManager mPackageManager;
103     private final Installer mInstaller;
104 
105     private final Handler mHandler;
106 
107     static {
verifyTronLoggingConstants()108         verifyTronLoggingConstants();
109     }
110 
ArtManagerService(Context context, Installer installer, Object ignored)111     public ArtManagerService(Context context, Installer installer,
112             Object ignored) {
113         mContext = context;
114         mInstaller = installer;
115         mHandler = new Handler(BackgroundThread.getHandler().getLooper());
116 
117         LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl());
118     }
119 
120     @NonNull
getPackageManager()121     private IPackageManager getPackageManager() {
122         if (mPackageManager == null) {
123             mPackageManager = IPackageManager.Stub.asInterface(
124                     ServiceManager.getService("package"));
125         }
126         return mPackageManager;
127     }
128 
checkAndroidPermissions(int callingUid, String callingPackage)129     private boolean checkAndroidPermissions(int callingUid, String callingPackage) {
130         // Callers always need this permission
131         mContext.enforceCallingOrSelfPermission(
132                 android.Manifest.permission.READ_RUNTIME_PROFILES, TAG);
133 
134         // Callers also need the ability to read usage statistics
135         switch (mContext.getSystemService(AppOpsManager.class)
136                 .noteOp(AppOpsManager.OP_GET_USAGE_STATS, callingUid, callingPackage)) {
137             case AppOpsManager.MODE_ALLOWED:
138                 return true;
139             case AppOpsManager.MODE_DEFAULT:
140                 mContext.enforceCallingOrSelfPermission(
141                         android.Manifest.permission.PACKAGE_USAGE_STATS, TAG);
142                 return true;
143             default:
144                 return false;
145         }
146     }
147 
148     /**
149      * Checks if the calling user is the shell user and if it is, it checks if it can
150      * to take a profile snapshot of the give package:
151      *   - on debuggable builds the shell user can take profile snapshots of any app.
152      *   - on non-debuggable builds the shell user can only take snapshots of debuggable apps.
153      *
154      * Returns true iff the callingUid is the shell uid and the shell is allowed snapshot profiles.
155      *
156      * Note that the root users will go through the regular {@link #checkAndroidPermissions) checks.
157      */
checkShellPermissions(@rofileType int profileType, String packageName, int callingUid)158     private boolean checkShellPermissions(@ProfileType int profileType, String packageName,
159             int callingUid) {
160         if (callingUid != Process.SHELL_UID) {
161             return false;
162         }
163         if (RoSystemProperties.DEBUGGABLE) {
164             return true;
165         }
166         if (profileType == ArtManager.PROFILE_BOOT_IMAGE) {
167             // The shell cannot profile the boot image on non-debuggable builds.
168             return false;
169         }
170         PackageInfo info = null;
171         try {
172             info =  getPackageManager().getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
173         } catch (RemoteException ignored) {
174             // Should not happen.
175         }
176         if (info == null) {
177             return false;
178         }
179 
180         // On user builds the shell can only profile debuggable apps.
181         return (info.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE)
182                 == ApplicationInfo.FLAG_DEBUGGABLE;
183     }
184 
185     @Override
snapshotRuntimeProfile(@rofileType int profileType, @Nullable String packageName, @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback, String callingPackage)186     public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
187             @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback,
188             String callingPackage) {
189         int callingUid = Binder.getCallingUid();
190         if (!checkShellPermissions(profileType, packageName, callingUid) &&
191                 !checkAndroidPermissions(callingUid, callingPackage)) {
192             try {
193                 callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
194             } catch (RemoteException ignored) {
195             }
196             return;
197         }
198 
199         // Validity checks on the arguments.
200         Objects.requireNonNull(callback);
201 
202         boolean bootImageProfile = profileType == ArtManager.PROFILE_BOOT_IMAGE;
203         if (!bootImageProfile) {
204             Preconditions.checkStringNotEmpty(codePath);
205             Preconditions.checkStringNotEmpty(packageName);
206         }
207 
208         // Verify that runtime profiling is enabled.
209         if (!isRuntimeProfilingEnabled(profileType, callingPackage)) {
210             throw new IllegalStateException("Runtime profiling is not enabled for " + profileType);
211         }
212 
213         if (DEBUG) {
214             Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath);
215         }
216 
217         if (bootImageProfile) {
218             snapshotBootImageProfile(callback);
219         } else {
220             snapshotAppProfile(packageName, codePath, callback);
221         }
222     }
223 
snapshotAppProfile( String packageName, String codePath, ISnapshotRuntimeProfileCallback callback)224     private void snapshotAppProfile(
225             String packageName, String codePath, ISnapshotRuntimeProfileCallback callback) {
226         PackageInfo info = null;
227         try {
228             // Note that we use the default user 0 to retrieve the package info.
229             // This doesn't really matter because for user 0 we always get a package back (even if
230             // it's not installed for the user 0). It is ok because we only care about the code
231             // paths and not if the package is enabled or not for the user.
232 
233             // TODO(calin): consider adding an API to PMS which can retrieve the
234             // PackageParser.Package.
235             info =  getPackageManager().getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
236         } catch (RemoteException ignored) {
237             // Should not happen.
238         }
239         if (info == null) {
240             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_PACKAGE_NOT_FOUND);
241             return;
242         }
243 
244         boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath);
245         String splitName = null;
246         String[] splitCodePaths = info.applicationInfo.getSplitCodePaths();
247         if (!pathFound && (splitCodePaths != null)) {
248             for (int i = splitCodePaths.length - 1; i >= 0; i--) {
249                 if (splitCodePaths[i].equals(codePath)) {
250                     pathFound = true;
251                     splitName = info.applicationInfo.splitNames[i];
252                     break;
253                 }
254             }
255         }
256         if (!pathFound) {
257             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND);
258             return;
259         }
260 
261         // All good, create the profile snapshot.
262         if (DexOptHelper.useArtService()) {
263             ParcelFileDescriptor fd;
264 
265             try (PackageManagerLocal.FilteredSnapshot snapshot =
266                             PackageManagerServiceUtils.getPackageManagerLocal()
267                                     .withFilteredSnapshot()) {
268                 fd = DexOptHelper.getArtManagerLocal().snapshotAppProfile(
269                         snapshot, packageName, splitName);
270             } catch (IllegalArgumentException e) {
271                 // ArtManagerLocal.snapshotAppProfile couldn't find the package or split. Since
272                 // we've checked them above this can only happen due to race, i.e. the package got
273                 // removed. So let's report it as SNAPSHOT_FAILED_PACKAGE_NOT_FOUND even if it was
274                 // for the split.
275                 // TODO(mast): Reuse the same snapshot to avoid this race.
276                 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_PACKAGE_NOT_FOUND);
277                 return;
278             } catch (IllegalStateException | ArtManagerLocal.SnapshotProfileException e) {
279                 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
280                 return;
281             }
282 
283             postSuccess(packageName, fd, callback);
284         } else {
285             int appId = UserHandle.getAppId(info.applicationInfo.uid);
286             if (appId < 0) {
287                 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
288                 Slog.wtf(TAG, "AppId is -1 for package: " + packageName);
289                 return;
290             }
291 
292             try {
293                 createProfileSnapshot(packageName, ArtManager.getProfileName(splitName), codePath,
294                         appId, callback);
295                 // Destroy the snapshot, we no longer need it.
296                 destroyProfileSnapshot(packageName, ArtManager.getProfileName(splitName));
297             } catch (LegacyDexoptDisabledException e) {
298                 throw new RuntimeException(e);
299             }
300         }
301     }
302 
createProfileSnapshot(String packageName, String profileName, String classpath, int appId, ISnapshotRuntimeProfileCallback callback)303     private void createProfileSnapshot(String packageName, String profileName, String classpath,
304             int appId, ISnapshotRuntimeProfileCallback callback)
305             throws LegacyDexoptDisabledException {
306         // Ask the installer to snapshot the profile.
307         try {
308             if (!mInstaller.createProfileSnapshot(appId, packageName, profileName, classpath)) {
309                 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
310                 return;
311             }
312         } catch (InstallerException e) {
313             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
314             return;
315         }
316 
317         // Open the snapshot and invoke the callback.
318         File snapshotProfile = ArtManager.getProfileSnapshotFileForName(packageName, profileName);
319 
320         ParcelFileDescriptor fd = null;
321         try {
322             fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY);
323             if (fd == null || !fd.getFileDescriptor().valid()) {
324                 postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
325             } else {
326                 postSuccess(packageName, fd, callback);
327             }
328         } catch (FileNotFoundException e) {
329             Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":"
330                     + snapshotProfile, e);
331             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
332         }
333     }
334 
destroyProfileSnapshot(String packageName, String profileName)335     private void destroyProfileSnapshot(String packageName, String profileName)
336             throws LegacyDexoptDisabledException {
337         if (DEBUG) {
338             Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + profileName);
339         }
340 
341         try {
342             mInstaller.destroyProfileSnapshot(packageName, profileName);
343         } catch (InstallerException e) {
344             Slog.e(TAG, "Failed to destroy profile snapshot for " + packageName + ":" + profileName,
345                     e);
346         }
347     }
348 
349     @Override
isRuntimeProfilingEnabled(@rofileType int profileType, String callingPackage)350     public boolean isRuntimeProfilingEnabled(@ProfileType int profileType, String callingPackage) {
351         int callingUid = Binder.getCallingUid();
352         if (callingUid != Process.SHELL_UID && !checkAndroidPermissions(callingUid, callingPackage)) {
353             return false;
354         }
355 
356         switch (profileType) {
357             case ArtManager.PROFILE_APPS :
358                 return true;
359             case ArtManager.PROFILE_BOOT_IMAGE:
360                 // The device config property overrides the system property version.
361                 boolean profileBootClassPath = SystemProperties.getBoolean(
362                         "persist.device_config.runtime_native_boot.profilebootclasspath",
363                         SystemProperties.getBoolean("dalvik.vm.profilebootclasspath", false));
364                 return (Build.IS_USERDEBUG || Build.IS_ENG) && profileBootClassPath;
365             default:
366                 throw new IllegalArgumentException("Invalid profile type:" + profileType);
367         }
368     }
369 
snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback)370     private void snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback) {
371         if (DexOptHelper.useArtService()) {
372             ParcelFileDescriptor fd;
373 
374             try (PackageManagerLocal.FilteredSnapshot snapshot =
375                             PackageManagerServiceUtils.getPackageManagerLocal()
376                                     .withFilteredSnapshot()) {
377                 fd = DexOptHelper.getArtManagerLocal().snapshotBootImageProfile(snapshot);
378             } catch (IllegalStateException | ArtManagerLocal.SnapshotProfileException e) {
379                 postError(callback, BOOT_IMAGE_ANDROID_PACKAGE,
380                         ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
381                 return;
382             }
383 
384             postSuccess(BOOT_IMAGE_ANDROID_PACKAGE, fd, callback);
385         } else {
386             // Combine the profiles for boot classpath and system server classpath.
387             // This avoids having yet another type of profiles and simplifies the processing.
388             String classpath = String.join(
389                     ":", Os.getenv("BOOTCLASSPATH"), Os.getenv("SYSTEMSERVERCLASSPATH"));
390 
391             final String standaloneSystemServerJars = Os.getenv("STANDALONE_SYSTEMSERVER_JARS");
392             if (standaloneSystemServerJars != null) {
393                 classpath = String.join(":", classpath, standaloneSystemServerJars);
394             }
395 
396             try {
397                 // Create the snapshot.
398                 createProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME,
399                         classpath,
400                         /*appId*/ -1, callback);
401                 // Destroy the snapshot, we no longer need it.
402                 destroyProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME);
403             } catch (LegacyDexoptDisabledException e) {
404                 throw new RuntimeException(e);
405             }
406         }
407     }
408 
409     /**
410      * Post {@link ISnapshotRuntimeProfileCallback#onError(int)} with the given error message
411      * on the internal {@code mHandler}.
412      */
postError(ISnapshotRuntimeProfileCallback callback, String packageName, int errCode)413     private void postError(ISnapshotRuntimeProfileCallback callback, String packageName,
414             int errCode) {
415         if (DEBUG) {
416             Slog.d(TAG, "Failed to snapshot profile for " + packageName + " with error: " +
417                     errCode);
418         }
419         mHandler.post(() -> {
420             try {
421                 callback.onError(errCode);
422             } catch (RemoteException | RuntimeException e) {
423                 Slog.w(TAG, "Failed to callback after profile snapshot for " + packageName, e);
424             }
425         });
426     }
427 
postSuccess(String packageName, ParcelFileDescriptor fd, ISnapshotRuntimeProfileCallback callback)428     private void postSuccess(String packageName, ParcelFileDescriptor fd,
429             ISnapshotRuntimeProfileCallback callback) {
430         if (DEBUG) {
431             Slog.d(TAG, "Successfully snapshot profile for " + packageName);
432         }
433         mHandler.post(() -> {
434             try {
435                 // Double check that the descriptor is still valid.
436                 // We've seen production issues (b/76028139) where this can turn invalid (there are
437                 // suspicions around the finalizer behaviour).
438                 if (fd.getFileDescriptor().valid()) {
439                     callback.onSuccess(fd);
440                 } else {
441                     Slog.wtf(TAG, "The snapshot FD became invalid before posting the result for "
442                             + packageName);
443                     callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
444                 }
445             } catch (RemoteException | RuntimeException e) {
446                 Slog.w(TAG,
447                         "Failed to call onSuccess after profile snapshot for " + packageName, e);
448             } finally {
449                 IoUtils.closeQuietly(fd);
450             }
451         });
452     }
453 
454     /**
455      * Prepare the application profiles.
456      * For all code paths:
457      *   - create the current primary profile to save time at app startup time.
458      *   - copy the profiles from the associated dex metadata file to the reference profile.
459      */
prepareAppProfiles(AndroidPackage pkg, @UserIdInt int user, boolean updateReferenceProfileContent)460     public void prepareAppProfiles(AndroidPackage pkg, @UserIdInt int user,
461             boolean updateReferenceProfileContent) throws LegacyDexoptDisabledException {
462         final int appId = UserHandle.getAppId(pkg.getUid());
463         if (user < 0) {
464             Slog.wtf(TAG, "Invalid user id: " + user);
465             return;
466         }
467         if (appId < 0) {
468             Slog.wtf(TAG, "Invalid app id: " + appId);
469             return;
470         }
471         try {
472             ArrayMap<String, String> codePathsProfileNames = getPackageProfileNames(pkg);
473             for (int i = codePathsProfileNames.size() - 1; i >= 0; i--) {
474                 String codePath = codePathsProfileNames.keyAt(i);
475                 String profileName = codePathsProfileNames.valueAt(i);
476                 String dexMetadataPath = null;
477                 // Passing the dex metadata file to the prepare method will update the reference
478                 // profile content. As such, we look for the dex metadata file only if we need to
479                 // perform an update.
480                 if (updateReferenceProfileContent) {
481                     File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath));
482                     dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
483                 }
484                 synchronized (mInstaller) {
485                     boolean result = mInstaller.prepareAppProfile(pkg.getPackageName(), user, appId,
486                             profileName, codePath, dexMetadataPath);
487                     if (!result) {
488                         Slog.e(TAG, "Failed to prepare profile for " +
489                                 pkg.getPackageName() + ":" + codePath);
490                     }
491                 }
492             }
493         } catch (InstallerException e) {
494             Slog.e(TAG, "Failed to prepare profile for " + pkg.getPackageName(), e);
495         }
496     }
497 
498     /**
499      * Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}.
500      */
prepareAppProfiles(AndroidPackage pkg, int[] user, boolean updateReferenceProfileContent)501     public void prepareAppProfiles(AndroidPackage pkg, int[] user,
502             boolean updateReferenceProfileContent) throws LegacyDexoptDisabledException {
503         for (int i = 0; i < user.length; i++) {
504             prepareAppProfiles(pkg, user[i], updateReferenceProfileContent);
505         }
506     }
507 
508     /**
509      * Clear the profiles for the given package.
510      */
clearAppProfiles(AndroidPackage pkg)511     public void clearAppProfiles(AndroidPackage pkg) throws LegacyDexoptDisabledException {
512         try {
513             ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
514             for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
515                 String profileName = packageProfileNames.valueAt(i);
516                 mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
517             }
518         } catch (InstallerException e) {
519             Slog.w(TAG, String.valueOf(e));
520         }
521     }
522 
523     /**
524      * Dumps the profiles for the given package.
525      */
dumpProfiles(AndroidPackage pkg, boolean dumpClassesAndMethods)526     public void dumpProfiles(AndroidPackage pkg, boolean dumpClassesAndMethods)
527             throws LegacyDexoptDisabledException {
528         final int sharedGid = UserHandle.getSharedAppGid(pkg.getUid());
529         try {
530             ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
531             for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
532                 String codePath = packageProfileNames.keyAt(i);
533                 String profileName = packageProfileNames.valueAt(i);
534                 mInstaller.dumpProfiles(sharedGid, pkg.getPackageName(), profileName, codePath,
535                                         dumpClassesAndMethods);
536             }
537         } catch (InstallerException e) {
538             Slog.w(TAG, "Failed to dump profiles", e);
539         }
540     }
541 
542     /**
543      * Compile layout resources in a given package.
544      */
compileLayouts(@onNull PackageState packageState, @NonNull AndroidPackage pkg)545     public boolean compileLayouts(@NonNull PackageState packageState, @NonNull AndroidPackage pkg) {
546         try {
547             final String packageName = pkg.getPackageName();
548             final String apkPath = pkg.getSplits().get(0).getPath();
549             // TODO(b/143971007): Use a cross-user directory
550             File dataDir = PackageInfoUtils.getDataDir(pkg, UserHandle.myUserId());
551             final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
552             if (packageState.isPrivileged() || pkg.isUseEmbeddedDex()
553                     || pkg.isDefaultToDeviceProtectedStorage()) {
554                 // Privileged apps prefer to load trusted code so they don't use compiled views.
555                 // If the app is not privileged but prefers code integrity, also avoid compiling
556                 // views.
557                 // Also disable the view compiler for protected storage apps since there are
558                 // selinux permissions required for writing to user_de.
559                 return false;
560             }
561             Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
562                     ") to " + outDexFile);
563             final long callingId = Binder.clearCallingIdentity();
564             try {
565                 return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
566                         pkg.getUid());
567             } finally {
568                 Binder.restoreCallingIdentity(callingId);
569             }
570         }
571         catch (Throwable e) {
572             Log.e("PackageManager", "Failed to compile layouts", e);
573             return false;
574         }
575     }
576 
577     /**
578      * Build the profiles names for all the package code paths (excluding resource only paths).
579      * Return the map [code path -> profile name].
580      */
getPackageProfileNames(AndroidPackage pkg)581     private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) {
582         ArrayMap<String, String> result = new ArrayMap<>();
583         if (pkg.isDeclaredHavingCode()) {
584             result.put(pkg.getBaseApkPath(), ArtManager.getProfileName(null));
585         }
586 
587         String[] splitCodePaths = pkg.getSplitCodePaths();
588         int[] splitFlags = pkg.getSplitFlags();
589         String[] splitNames = pkg.getSplitNames();
590         if (!ArrayUtils.isEmpty(splitCodePaths)) {
591             for (int i = 0; i < splitCodePaths.length; i++) {
592                 if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
593                     result.put(splitCodePaths[i], ArtManager.getProfileName(splitNames[i]));
594                 }
595             }
596         }
597         return result;
598     }
599 
600     // Constants used for logging compilation filter to TRON.
601     // DO NOT CHANGE existing values.
602     //
603     // NOTE: '-1' value is reserved for the case where we cannot produce a valid
604     // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the
605     // ActivityMetricsLoggers.
606     private static final int TRON_COMPILATION_FILTER_ERROR = 0;
607     private static final int TRON_COMPILATION_FILTER_UNKNOWN = 1;
608     private static final int TRON_COMPILATION_FILTER_ASSUMED_VERIFIED = 2;
609     private static final int TRON_COMPILATION_FILTER_EXTRACT = 3;
610     private static final int TRON_COMPILATION_FILTER_VERIFY = 4;
611     private static final int TRON_COMPILATION_FILTER_QUICKEN = 5;
612     private static final int TRON_COMPILATION_FILTER_SPACE_PROFILE = 6;
613     private static final int TRON_COMPILATION_FILTER_SPACE = 7;
614     private static final int TRON_COMPILATION_FILTER_SPEED_PROFILE = 8;
615     private static final int TRON_COMPILATION_FILTER_SPEED = 9;
616     private static final int TRON_COMPILATION_FILTER_EVERYTHING_PROFILE = 10;
617     private static final int TRON_COMPILATION_FILTER_EVERYTHING = 11;
618     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK = 12;
619     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK = 13;
620     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK = 14;
621     // Filter with IORap
622     private static final int TRON_COMPILATION_FILTER_ASSUMED_VERIFIED_IORAP = 15;
623     private static final int TRON_COMPILATION_FILTER_EXTRACT_IORAP = 16;
624     private static final int TRON_COMPILATION_FILTER_VERIFY_IORAP = 17;
625     private static final int TRON_COMPILATION_FILTER_QUICKEN_IORAP = 18;
626     private static final int TRON_COMPILATION_FILTER_SPACE_PROFILE_IORAP = 19;
627     private static final int TRON_COMPILATION_FILTER_SPACE_IORAP = 20;
628     private static final int TRON_COMPILATION_FILTER_SPEED_PROFILE_IORAP = 21;
629     private static final int TRON_COMPILATION_FILTER_SPEED_IORAP = 22;
630     private static final int TRON_COMPILATION_FILTER_EVERYTHING_PROFILE_IORAP = 23;
631     private static final int TRON_COMPILATION_FILTER_EVERYTHING_IORAP = 24;
632     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_IORAP = 25;
633     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK_IORAP = 26;
634     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK_IORAP = 27;
635 
636     // Constants used for logging compilation reason to TRON.
637     // DO NOT CHANGE existing values.
638     //
639     // In the below constants, the abbreviation DM stands for "DEX metadata".
640     //
641     // NOTE: '-1' value is reserved for the case where we cannot produce a valid
642     // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the
643     // ActivityMetricsLoggers.
644     private static final int TRON_COMPILATION_REASON_ERROR = 0;
645     private static final int TRON_COMPILATION_REASON_UNKNOWN = 1;
646     private static final int TRON_COMPILATION_REASON_FIRST_BOOT = 2;
647     private static final int TRON_COMPILATION_REASON_BOOT_DEPRECATED_SINCE_S = 3;
648     private static final int TRON_COMPILATION_REASON_INSTALL = 4;
649     private static final int TRON_COMPILATION_REASON_BG_DEXOPT = 5;
650     private static final int TRON_COMPILATION_REASON_AB_OTA = 6;
651     private static final int TRON_COMPILATION_REASON_INACTIVE = 7;
652     private static final int TRON_COMPILATION_REASON_SHARED = 8;
653     private static final int TRON_COMPILATION_REASON_INSTALL_WITH_DM = 9;
654     private static final int TRON_COMPILATION_REASON_INSTALL_FAST = 10;
655     private static final int TRON_COMPILATION_REASON_INSTALL_BULK = 11;
656     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY = 12;
657     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED = 13;
658     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 14;
659     private static final int TRON_COMPILATION_REASON_INSTALL_FAST_WITH_DM = 15;
660     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_WITH_DM = 16;
661     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_WITH_DM = 17;
662     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED_WITH_DM = 18;
663     private static final int
664             TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM = 19;
665     private static final int TRON_COMPILATION_REASON_BOOT_AFTER_OTA = 20;
666     private static final int TRON_COMPILATION_REASON_POST_BOOT = 21;
667     private static final int TRON_COMPILATION_REASON_CMDLINE = 22;
668     private static final int TRON_COMPILATION_REASON_PREBUILT = 23;
669     private static final int TRON_COMPILATION_REASON_VDEX = 24;
670     private static final int TRON_COMPILATION_REASON_BOOT_AFTER_MAINLINE_UPDATE = 25;
671 
672     // The annotation to add as a suffix to the compilation reason when dexopt was
673     // performed with dex metadata.
674     public static final String DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION = "-dm";
675 
676     /**
677      * Convert the compilation reason to an int suitable to be logged to TRON.
678      */
getCompilationReasonTronValue(String compilationReason)679     private static int getCompilationReasonTronValue(String compilationReason) {
680         switch (compilationReason) {
681             case "cmdline" : return TRON_COMPILATION_REASON_CMDLINE;
682             case "error" : return TRON_COMPILATION_REASON_ERROR;
683             case "first-boot" : return TRON_COMPILATION_REASON_FIRST_BOOT;
684             case "boot-after-ota": return TRON_COMPILATION_REASON_BOOT_AFTER_OTA;
685             case "boot-after-mainline-update":
686                 return TRON_COMPILATION_REASON_BOOT_AFTER_MAINLINE_UPDATE;
687             case "post-boot" : return TRON_COMPILATION_REASON_POST_BOOT;
688             case "install" : return TRON_COMPILATION_REASON_INSTALL;
689             case "bg-dexopt" : return TRON_COMPILATION_REASON_BG_DEXOPT;
690             case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA;
691             case "inactive" : return TRON_COMPILATION_REASON_INACTIVE;
692             case "shared" : return TRON_COMPILATION_REASON_SHARED;
693             case "prebuilt" : return TRON_COMPILATION_REASON_PREBUILT;
694             case "vdex" : return TRON_COMPILATION_REASON_VDEX;
695             case "install-fast" :
696                 return TRON_COMPILATION_REASON_INSTALL_FAST;
697             case "install-bulk" :
698                 return TRON_COMPILATION_REASON_INSTALL_BULK;
699             case "install-bulk-secondary" :
700                 return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
701             case "install-bulk-downgraded" :
702                 return TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
703             case "install-bulk-secondary-downgraded" :
704                 return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
705             // These are special markers for dex metadata installation that do not
706             // have an equivalent as a system property.
707             case "install" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
708                 return TRON_COMPILATION_REASON_INSTALL_WITH_DM;
709             case "install-fast" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
710                 return TRON_COMPILATION_REASON_INSTALL_FAST_WITH_DM;
711             case "install-bulk" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
712                 return TRON_COMPILATION_REASON_INSTALL_BULK_WITH_DM;
713             case "install-bulk-secondary" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
714                 return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_WITH_DM;
715             case "install-bulk-downgraded" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
716                 return TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED_WITH_DM;
717             case "install-bulk-secondary-downgraded" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
718                 return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM;
719             default: return TRON_COMPILATION_REASON_UNKNOWN;
720         }
721     }
722 
723     /**
724      * Convert the compilation filter to an int suitable to be logged to TRON.
725      */
getCompilationFilterTronValue(String compilationFilter)726     private static int getCompilationFilterTronValue(String compilationFilter) {
727         switch (compilationFilter) {
728             case "error" : return TRON_COMPILATION_FILTER_ERROR;
729             case "unknown" : return TRON_COMPILATION_FILTER_UNKNOWN;
730             case "assume-verified" : return TRON_COMPILATION_FILTER_ASSUMED_VERIFIED;
731             case "extract" : return TRON_COMPILATION_FILTER_EXTRACT;
732             case "verify" : return TRON_COMPILATION_FILTER_VERIFY;
733             case "quicken" : return TRON_COMPILATION_FILTER_QUICKEN;
734             case "space-profile" : return TRON_COMPILATION_FILTER_SPACE_PROFILE;
735             case "space" : return TRON_COMPILATION_FILTER_SPACE;
736             case "speed-profile" : return TRON_COMPILATION_FILTER_SPEED_PROFILE;
737             case "speed" : return TRON_COMPILATION_FILTER_SPEED;
738             case "everything-profile" : return TRON_COMPILATION_FILTER_EVERYTHING_PROFILE;
739             case "everything" : return TRON_COMPILATION_FILTER_EVERYTHING;
740             case "run-from-apk" : return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK;
741             case "run-from-apk-fallback" :
742                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
743             case "run-from-vdex-fallback" :
744                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
745             case "assume-verified-iorap" : return TRON_COMPILATION_FILTER_ASSUMED_VERIFIED_IORAP;
746             case "extract-iorap" : return TRON_COMPILATION_FILTER_EXTRACT_IORAP;
747             case "verify-iorap" : return TRON_COMPILATION_FILTER_VERIFY_IORAP;
748             case "quicken-iorap" : return TRON_COMPILATION_FILTER_QUICKEN_IORAP;
749             case "space-profile-iorap" : return TRON_COMPILATION_FILTER_SPACE_PROFILE_IORAP;
750             case "space-iorap" : return TRON_COMPILATION_FILTER_SPACE_IORAP;
751             case "speed-profile-iorap" : return TRON_COMPILATION_FILTER_SPEED_PROFILE_IORAP;
752             case "speed-iorap" : return TRON_COMPILATION_FILTER_SPEED_IORAP;
753             case "everything-profile-iorap" :
754                 return TRON_COMPILATION_FILTER_EVERYTHING_PROFILE_IORAP;
755             case "everything-iorap" : return TRON_COMPILATION_FILTER_EVERYTHING_IORAP;
756             case "run-from-apk-iorap" : return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_IORAP;
757             case "run-from-apk-fallback-iorap" :
758                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK_IORAP;
759             case "run-from-vdex-fallback-iorap" :
760                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK_IORAP;
761             default: return TRON_COMPILATION_FILTER_UNKNOWN;
762         }
763     }
764 
verifyTronLoggingConstants()765     private static void verifyTronLoggingConstants() {
766         for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
767             String reason = PackageManagerServiceCompilerMapping.REASON_STRINGS[i];
768             int value = getCompilationReasonTronValue(reason);
769             if (value == TRON_COMPILATION_REASON_ERROR
770                     || value == TRON_COMPILATION_REASON_UNKNOWN) {
771                 throw new IllegalArgumentException("Compilation reason not configured for TRON "
772                         + "logging: " + reason);
773             }
774         }
775     }
776 
777     private class ArtManagerInternalImpl extends ArtManagerInternal {
778         private static final String IORAP_DIR = "/data/misc/iorapd";
779         private static final String TAG = "ArtManagerInternalImpl";
780 
781         @Override
getPackageOptimizationInfo( ApplicationInfo info, String abi, String activityName)782         public PackageOptimizationInfo getPackageOptimizationInfo(
783                 ApplicationInfo info, String abi, String activityName) {
784             if (info.packageName.equals(PackageManagerService.PLATFORM_PACKAGE_NAME)) {
785                 // PackageManagerService.PLATFORM_PACKAGE_NAME in this context means that the
786                 // activity is defined in bootclasspath. Currently, we don't have an API to get the
787                 // correct optimization info.
788                 return PackageOptimizationInfo.createWithNoInfo();
789             }
790 
791             String compilationReason;
792             String compilationFilter;
793             try {
794                 String isa = VMRuntime.getInstructionSet(abi);
795                 DexFile.OptimizationInfo optInfo =
796                         DexFile.getDexFileOptimizationInfo(info.getBaseCodePath(), isa);
797                 compilationFilter = optInfo.getStatus();
798                 compilationReason = optInfo.getReason();
799             } catch (FileNotFoundException e) {
800                 Slog.e(TAG, "Could not get optimizations status for " + info.getBaseCodePath(), e);
801                 compilationFilter = "error";
802                 compilationReason = "error";
803             } catch (IllegalArgumentException e) {
804                 Slog.wtf(TAG, "Requested optimization status for " + info.getBaseCodePath()
805                         + " due to an invalid abi " + abi, e);
806                 compilationFilter = "error";
807                 compilationReason = "error";
808             }
809 
810             if (checkIorapCompiledTrace(info.packageName, activityName, info.longVersionCode)) {
811                 compilationFilter = compilationFilter + "-iorap";
812             }
813 
814             int compilationFilterTronValue = getCompilationFilterTronValue(compilationFilter);
815             int compilationReasonTronValue = getCompilationReasonTronValue(compilationReason);
816 
817             return new PackageOptimizationInfo(
818                     compilationFilterTronValue, compilationReasonTronValue);
819         }
820 
821         /*
822          * Checks the existence of IORap compiled trace for an app.
823          *
824          * @return true if the compiled trace exists and the size is greater than 1kb.
825          */
checkIorapCompiledTrace( String packageName, String activityName, long version)826         private boolean checkIorapCompiledTrace(
827                 String packageName, String activityName, long version) {
828             // For example: /data/misc/iorapd/com.google.android.GoogleCamera/
829             // 60092239/com.android.camera.CameraLauncher/compiled_traces/compiled_trace.pb
830             Path tracePath = Paths.get(IORAP_DIR,
831                                        packageName,
832                                        Long.toString(version),
833                                        activityName,
834                                        "compiled_traces",
835                                        "compiled_trace.pb");
836             try {
837                 boolean exists =  Files.exists(tracePath);
838                 if (DEBUG) {
839                     Log.d(TAG, tracePath.toString() + (exists? " exists" : " doesn't exist"));
840                 }
841                 if (exists) {
842                     long bytes = Files.size(tracePath);
843                     if (DEBUG) {
844                         Log.d(TAG, tracePath.toString() + " size is " + Long.toString(bytes));
845                     }
846                     return bytes > 0L;
847                 }
848                 return exists;
849             } catch (IOException e) {
850                 Log.d(TAG, e.getMessage());
851                 return false;
852             }
853         }
854     }
855 }
856