• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.AppOpsManager;
22 import android.content.Context;
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.IPackageManager;
25 import android.content.pm.PackageInfo;
26 import android.content.pm.PackageManager;
27 import android.content.pm.dex.ArtManager;
28 import android.content.pm.dex.ArtManager.ProfileType;
29 import android.content.pm.dex.ArtManagerInternal;
30 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
31 import android.content.pm.dex.PackageOptimizationInfo;
32 import android.os.Binder;
33 import android.os.Build;
34 import android.os.Handler;
35 import android.os.ParcelFileDescriptor;
36 import android.os.Process;
37 import android.os.RemoteException;
38 import android.os.ServiceManager;
39 import android.os.SystemProperties;
40 import android.util.ArrayMap;
41 import android.util.Log;
42 import android.util.Slog;
43 
44 import com.android.internal.os.BackgroundThread;
45 import com.android.internal.os.RoSystemProperties;
46 import com.android.internal.util.ArrayUtils;
47 import com.android.internal.util.Preconditions;
48 import com.android.server.LocalServices;
49 import com.android.server.art.ArtManagerLocal;
50 import com.android.server.pm.DexOptHelper;
51 import com.android.server.pm.Installer;
52 import com.android.server.pm.PackageManagerLocal;
53 import com.android.server.pm.PackageManagerService;
54 import com.android.server.pm.PackageManagerServiceCompilerMapping;
55 import com.android.server.pm.PackageManagerServiceUtils;
56 import com.android.server.pm.pkg.AndroidPackage;
57 
58 import dalvik.system.DexFile;
59 import dalvik.system.VMRuntime;
60 
61 import libcore.io.IoUtils;
62 
63 import java.io.FileNotFoundException;
64 import java.io.IOException;
65 import java.nio.file.Files;
66 import java.nio.file.Path;
67 import java.nio.file.Paths;
68 import java.util.Objects;
69 
70 /**
71  * A system service that provides access to runtime and compiler artifacts.
72  *
73  * This service is not accessed by users directly, instead one uses an instance of
74  * {@link ArtManager}, which can be accessed via {@link PackageManager} as follows:
75  * <p/>
76  * {@code context().getPackageManager().getArtManager();}
77  * <p class="note">
78  * Note: Accessing runtime artifacts may require extra permissions. For example querying the
79  * runtime profiles of apps requires {@link android.Manifest.permission#READ_RUNTIME_PROFILES}
80  * which is a system-level permission that will not be granted to normal apps.
81  */
82 public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
83     private static final String TAG = "ArtManagerService";
84     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
85 
86     // Package name used to create the profile directory layout when
87     // taking a snapshot of the boot image profile.
88     private static final String BOOT_IMAGE_ANDROID_PACKAGE = "android";
89     // Profile name used for the boot image profile.
90     private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof";
91 
92     private final Context mContext;
93     private IPackageManager mPackageManager;
94     private final Installer mInstaller;
95 
96     private final Handler mHandler;
97 
98     static {
verifyTronLoggingConstants()99         verifyTronLoggingConstants();
100     }
101 
ArtManagerService(Context context, Installer installer, Object ignored)102     public ArtManagerService(Context context, Installer installer,
103             Object ignored) {
104         mContext = context;
105         mInstaller = installer;
106         mHandler = new Handler(BackgroundThread.getHandler().getLooper());
107 
108         LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl());
109     }
110 
111     @NonNull
getPackageManager()112     private IPackageManager getPackageManager() {
113         if (mPackageManager == null) {
114             mPackageManager = IPackageManager.Stub.asInterface(
115                     ServiceManager.getService("package"));
116         }
117         return mPackageManager;
118     }
119 
checkAndroidPermissions(int callingUid, String callingPackage)120     private boolean checkAndroidPermissions(int callingUid, String callingPackage) {
121         // Callers always need this permission
122         mContext.enforceCallingOrSelfPermission(
123                 android.Manifest.permission.READ_RUNTIME_PROFILES, TAG);
124 
125         // Callers also need the ability to read usage statistics
126         switch (mContext.getSystemService(AppOpsManager.class)
127                 .noteOp(AppOpsManager.OP_GET_USAGE_STATS, callingUid, callingPackage)) {
128             case AppOpsManager.MODE_ALLOWED:
129                 return true;
130             case AppOpsManager.MODE_DEFAULT:
131                 mContext.enforceCallingOrSelfPermission(
132                         android.Manifest.permission.PACKAGE_USAGE_STATS, TAG);
133                 return true;
134             default:
135                 return false;
136         }
137     }
138 
139     /**
140      * Checks if the calling user is the shell user and if it is, it checks if it can
141      * to take a profile snapshot of the give package:
142      *   - on debuggable builds the shell user can take profile snapshots of any app.
143      *   - on non-debuggable builds the shell user can only take snapshots of debuggable apps.
144      *
145      * Returns true iff the callingUid is the shell uid and the shell is allowed snapshot profiles.
146      *
147      * Note that the root users will go through the regular {@link #checkAndroidPermissions) checks.
148      */
checkShellPermissions(@rofileType int profileType, String packageName, int callingUid)149     private boolean checkShellPermissions(@ProfileType int profileType, String packageName,
150             int callingUid) {
151         if (callingUid != Process.SHELL_UID) {
152             return false;
153         }
154         if (RoSystemProperties.DEBUGGABLE) {
155             return true;
156         }
157         if (profileType == ArtManager.PROFILE_BOOT_IMAGE) {
158             // The shell cannot profile the boot image on non-debuggable builds.
159             return false;
160         }
161         PackageInfo info = null;
162         try {
163             info =  getPackageManager().getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
164         } catch (RemoteException ignored) {
165             // Should not happen.
166         }
167         if (info == null) {
168             return false;
169         }
170 
171         // On user builds the shell can only profile debuggable apps.
172         return (info.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE)
173                 == ApplicationInfo.FLAG_DEBUGGABLE;
174     }
175 
176     @Override
snapshotRuntimeProfile(@rofileType int profileType, @Nullable String packageName, @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback, String callingPackage)177     public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
178             @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback,
179             String callingPackage) {
180         int callingUid = Binder.getCallingUid();
181         if (!checkShellPermissions(profileType, packageName, callingUid) &&
182                 !checkAndroidPermissions(callingUid, callingPackage)) {
183             try {
184                 callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
185             } catch (RemoteException ignored) {
186             }
187             return;
188         }
189 
190         // Validity checks on the arguments.
191         Objects.requireNonNull(callback);
192 
193         boolean bootImageProfile = profileType == ArtManager.PROFILE_BOOT_IMAGE;
194         if (!bootImageProfile) {
195             Preconditions.checkStringNotEmpty(codePath);
196             Preconditions.checkStringNotEmpty(packageName);
197         }
198 
199         // Verify that runtime profiling is enabled.
200         if (!isRuntimeProfilingEnabled(profileType, callingPackage)) {
201             throw new IllegalStateException("Runtime profiling is not enabled for " + profileType);
202         }
203 
204         if (DEBUG) {
205             Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath);
206         }
207 
208         if (bootImageProfile) {
209             snapshotBootImageProfile(callback);
210         } else {
211             snapshotAppProfile(packageName, codePath, callback);
212         }
213     }
214 
snapshotAppProfile( String packageName, String codePath, ISnapshotRuntimeProfileCallback callback)215     private void snapshotAppProfile(
216             String packageName, String codePath, ISnapshotRuntimeProfileCallback callback) {
217         PackageInfo info = null;
218         try {
219             // Note that we use the default user 0 to retrieve the package info.
220             // This doesn't really matter because for user 0 we always get a package back (even if
221             // it's not installed for the user 0). It is ok because we only care about the code
222             // paths and not if the package is enabled or not for the user.
223 
224             // TODO(calin): consider adding an API to PMS which can retrieve the
225             // PackageParser.Package.
226             info =  getPackageManager().getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
227         } catch (RemoteException ignored) {
228             // Should not happen.
229         }
230         if (info == null) {
231             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_PACKAGE_NOT_FOUND);
232             return;
233         }
234 
235         boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath);
236         String splitName = null;
237         String[] splitCodePaths = info.applicationInfo.getSplitCodePaths();
238         if (!pathFound && (splitCodePaths != null)) {
239             for (int i = splitCodePaths.length - 1; i >= 0; i--) {
240                 if (splitCodePaths[i].equals(codePath)) {
241                     pathFound = true;
242                     splitName = info.applicationInfo.splitNames[i];
243                     break;
244                 }
245             }
246         }
247         if (!pathFound) {
248             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND);
249             return;
250         }
251 
252         // All good, create the profile snapshot.
253         ParcelFileDescriptor fd;
254 
255         try (PackageManagerLocal.FilteredSnapshot snapshot =
256                         PackageManagerServiceUtils.getPackageManagerLocal()
257                                 .withFilteredSnapshot()) {
258             fd = DexOptHelper.getArtManagerLocal().snapshotAppProfile(
259                     snapshot, packageName, splitName);
260         } catch (IllegalArgumentException e) {
261             // ArtManagerLocal.snapshotAppProfile couldn't find the package or split. Since
262             // we've checked them above this can only happen due to race, i.e. the package got
263             // removed. So let's report it as SNAPSHOT_FAILED_PACKAGE_NOT_FOUND even if it was
264             // for the split.
265             // TODO(mast): Reuse the same snapshot to avoid this race.
266             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_PACKAGE_NOT_FOUND);
267             return;
268         } catch (IllegalStateException | ArtManagerLocal.SnapshotProfileException e) {
269             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
270             return;
271         }
272 
273         postSuccess(packageName, fd, callback);
274     }
275 
276     @Override
isRuntimeProfilingEnabled(@rofileType int profileType, String callingPackage)277     public boolean isRuntimeProfilingEnabled(@ProfileType int profileType, String callingPackage) {
278         int callingUid = Binder.getCallingUid();
279         if (callingUid != Process.SHELL_UID && !checkAndroidPermissions(callingUid, callingPackage)) {
280             return false;
281         }
282 
283         switch (profileType) {
284             case ArtManager.PROFILE_APPS :
285                 return true;
286             case ArtManager.PROFILE_BOOT_IMAGE:
287                 // The device config property overrides the system property version.
288                 boolean profileBootClassPath = SystemProperties.getBoolean(
289                         "persist.device_config.runtime_native_boot.profilebootclasspath",
290                         SystemProperties.getBoolean("dalvik.vm.profilebootclasspath", false));
291                 return (Build.IS_USERDEBUG || Build.IS_ENG) && profileBootClassPath;
292             default:
293                 throw new IllegalArgumentException("Invalid profile type:" + profileType);
294         }
295     }
296 
snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback)297     private void snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback) {
298         ParcelFileDescriptor fd;
299 
300         try (PackageManagerLocal.FilteredSnapshot snapshot =
301                         PackageManagerServiceUtils.getPackageManagerLocal()
302                                 .withFilteredSnapshot()) {
303             fd = DexOptHelper.getArtManagerLocal().snapshotBootImageProfile(snapshot);
304         } catch (IllegalStateException | ArtManagerLocal.SnapshotProfileException e) {
305             postError(callback, BOOT_IMAGE_ANDROID_PACKAGE,
306                     ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
307             return;
308         }
309 
310         postSuccess(BOOT_IMAGE_ANDROID_PACKAGE, fd, callback);
311     }
312 
313     /**
314      * Post {@link ISnapshotRuntimeProfileCallback#onError(int)} with the given error message
315      * on the internal {@code mHandler}.
316      */
postError(ISnapshotRuntimeProfileCallback callback, String packageName, int errCode)317     private void postError(ISnapshotRuntimeProfileCallback callback, String packageName,
318             int errCode) {
319         if (DEBUG) {
320             Slog.d(TAG, "Failed to snapshot profile for " + packageName + " with error: " +
321                     errCode);
322         }
323         mHandler.post(() -> {
324             try {
325                 callback.onError(errCode);
326             } catch (RemoteException | RuntimeException e) {
327                 Slog.w(TAG, "Failed to callback after profile snapshot for " + packageName, e);
328             }
329         });
330     }
331 
postSuccess(String packageName, ParcelFileDescriptor fd, ISnapshotRuntimeProfileCallback callback)332     private void postSuccess(String packageName, ParcelFileDescriptor fd,
333             ISnapshotRuntimeProfileCallback callback) {
334         if (DEBUG) {
335             Slog.d(TAG, "Successfully snapshot profile for " + packageName);
336         }
337         mHandler.post(() -> {
338             try {
339                 // Double check that the descriptor is still valid.
340                 // We've seen production issues (b/76028139) where this can turn invalid (there are
341                 // suspicions around the finalizer behaviour).
342                 if (fd.getFileDescriptor().valid()) {
343                     callback.onSuccess(fd);
344                 } else {
345                     Slog.wtf(TAG, "The snapshot FD became invalid before posting the result for "
346                             + packageName);
347                     callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
348                 }
349             } catch (RemoteException | RuntimeException e) {
350                 Slog.w(TAG,
351                         "Failed to call onSuccess after profile snapshot for " + packageName, e);
352             } finally {
353                 IoUtils.closeQuietly(fd);
354             }
355         });
356     }
357 
358     // Constants used for logging compilation filter to TRON.
359     // DO NOT CHANGE existing values.
360     //
361     // NOTE: '-1' value is reserved for the case where we cannot produce a valid
362     // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the
363     // ActivityMetricsLoggers.
364     private static final int TRON_COMPILATION_FILTER_ERROR = 0;
365     private static final int TRON_COMPILATION_FILTER_UNKNOWN = 1;
366     private static final int TRON_COMPILATION_FILTER_ASSUMED_VERIFIED = 2;
367     private static final int TRON_COMPILATION_FILTER_EXTRACT = 3;
368     private static final int TRON_COMPILATION_FILTER_VERIFY = 4;
369     private static final int TRON_COMPILATION_FILTER_QUICKEN = 5;
370     private static final int TRON_COMPILATION_FILTER_SPACE_PROFILE = 6;
371     private static final int TRON_COMPILATION_FILTER_SPACE = 7;
372     private static final int TRON_COMPILATION_FILTER_SPEED_PROFILE = 8;
373     private static final int TRON_COMPILATION_FILTER_SPEED = 9;
374     private static final int TRON_COMPILATION_FILTER_EVERYTHING_PROFILE = 10;
375     private static final int TRON_COMPILATION_FILTER_EVERYTHING = 11;
376     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK = 12;
377     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK = 13;
378     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK = 14;
379     // Filter with IORap
380     private static final int TRON_COMPILATION_FILTER_ASSUMED_VERIFIED_IORAP = 15;
381     private static final int TRON_COMPILATION_FILTER_EXTRACT_IORAP = 16;
382     private static final int TRON_COMPILATION_FILTER_VERIFY_IORAP = 17;
383     private static final int TRON_COMPILATION_FILTER_QUICKEN_IORAP = 18;
384     private static final int TRON_COMPILATION_FILTER_SPACE_PROFILE_IORAP = 19;
385     private static final int TRON_COMPILATION_FILTER_SPACE_IORAP = 20;
386     private static final int TRON_COMPILATION_FILTER_SPEED_PROFILE_IORAP = 21;
387     private static final int TRON_COMPILATION_FILTER_SPEED_IORAP = 22;
388     private static final int TRON_COMPILATION_FILTER_EVERYTHING_PROFILE_IORAP = 23;
389     private static final int TRON_COMPILATION_FILTER_EVERYTHING_IORAP = 24;
390     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_IORAP = 25;
391     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK_IORAP = 26;
392     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK_IORAP = 27;
393 
394     // Constants used for logging compilation reason to TRON.
395     // DO NOT CHANGE existing values.
396     //
397     // In the below constants, the abbreviation DM stands for "DEX metadata".
398     //
399     // NOTE: '-1' value is reserved for the case where we cannot produce a valid
400     // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the
401     // ActivityMetricsLoggers.
402     private static final int TRON_COMPILATION_REASON_ERROR = 0;
403     private static final int TRON_COMPILATION_REASON_UNKNOWN = 1;
404     private static final int TRON_COMPILATION_REASON_FIRST_BOOT = 2;
405     private static final int TRON_COMPILATION_REASON_BOOT_DEPRECATED_SINCE_S = 3;
406     private static final int TRON_COMPILATION_REASON_INSTALL = 4;
407     private static final int TRON_COMPILATION_REASON_BG_DEXOPT = 5;
408     private static final int TRON_COMPILATION_REASON_AB_OTA = 6;
409     private static final int TRON_COMPILATION_REASON_INACTIVE = 7;
410     private static final int TRON_COMPILATION_REASON_SHARED = 8;
411     private static final int TRON_COMPILATION_REASON_INSTALL_WITH_DM = 9;
412     private static final int TRON_COMPILATION_REASON_INSTALL_FAST = 10;
413     private static final int TRON_COMPILATION_REASON_INSTALL_BULK = 11;
414     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY = 12;
415     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED = 13;
416     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 14;
417     private static final int TRON_COMPILATION_REASON_INSTALL_FAST_WITH_DM = 15;
418     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_WITH_DM = 16;
419     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_WITH_DM = 17;
420     private static final int TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED_WITH_DM = 18;
421     private static final int
422             TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM = 19;
423     private static final int TRON_COMPILATION_REASON_BOOT_AFTER_OTA = 20;
424     private static final int TRON_COMPILATION_REASON_POST_BOOT = 21;
425     private static final int TRON_COMPILATION_REASON_CMDLINE = 22;
426     private static final int TRON_COMPILATION_REASON_PREBUILT = 23;
427     private static final int TRON_COMPILATION_REASON_VDEX = 24;
428     private static final int TRON_COMPILATION_REASON_BOOT_AFTER_MAINLINE_UPDATE = 25;
429 
430     // The annotation to add as a suffix to the compilation reason when dexopt was
431     // performed with dex metadata.
432     public static final String DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION = "-dm";
433 
434     /**
435      * Convert the compilation reason to an int suitable to be logged to TRON.
436      */
getCompilationReasonTronValue(String compilationReason)437     private static int getCompilationReasonTronValue(String compilationReason) {
438         switch (compilationReason) {
439             case "cmdline" : return TRON_COMPILATION_REASON_CMDLINE;
440             case "error" : return TRON_COMPILATION_REASON_ERROR;
441             case "first-boot" : return TRON_COMPILATION_REASON_FIRST_BOOT;
442             case "boot-after-ota": return TRON_COMPILATION_REASON_BOOT_AFTER_OTA;
443             case "boot-after-mainline-update":
444                 return TRON_COMPILATION_REASON_BOOT_AFTER_MAINLINE_UPDATE;
445             case "post-boot" : return TRON_COMPILATION_REASON_POST_BOOT;
446             case "install" : return TRON_COMPILATION_REASON_INSTALL;
447             case "bg-dexopt" : return TRON_COMPILATION_REASON_BG_DEXOPT;
448             case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA;
449             case "inactive" : return TRON_COMPILATION_REASON_INACTIVE;
450             case "shared" : return TRON_COMPILATION_REASON_SHARED;
451             case "prebuilt" : return TRON_COMPILATION_REASON_PREBUILT;
452             case "vdex" : return TRON_COMPILATION_REASON_VDEX;
453             case "install-fast" :
454                 return TRON_COMPILATION_REASON_INSTALL_FAST;
455             case "install-bulk" :
456                 return TRON_COMPILATION_REASON_INSTALL_BULK;
457             case "install-bulk-secondary" :
458                 return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
459             case "install-bulk-downgraded" :
460                 return TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
461             case "install-bulk-secondary-downgraded" :
462                 return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
463             // These are special markers for dex metadata installation that do not
464             // have an equivalent as a system property.
465             case "install" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
466                 return TRON_COMPILATION_REASON_INSTALL_WITH_DM;
467             case "install-fast" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
468                 return TRON_COMPILATION_REASON_INSTALL_FAST_WITH_DM;
469             case "install-bulk" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
470                 return TRON_COMPILATION_REASON_INSTALL_BULK_WITH_DM;
471             case "install-bulk-secondary" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
472                 return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_WITH_DM;
473             case "install-bulk-downgraded" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
474                 return TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED_WITH_DM;
475             case "install-bulk-secondary-downgraded" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
476                 return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM;
477             default: return TRON_COMPILATION_REASON_UNKNOWN;
478         }
479     }
480 
481     /**
482      * Convert the compilation filter to an int suitable to be logged to TRON.
483      */
getCompilationFilterTronValue(String compilationFilter)484     private static int getCompilationFilterTronValue(String compilationFilter) {
485         switch (compilationFilter) {
486             case "error" : return TRON_COMPILATION_FILTER_ERROR;
487             case "unknown" : return TRON_COMPILATION_FILTER_UNKNOWN;
488             case "assume-verified" : return TRON_COMPILATION_FILTER_ASSUMED_VERIFIED;
489             case "extract" : return TRON_COMPILATION_FILTER_EXTRACT;
490             case "verify" : return TRON_COMPILATION_FILTER_VERIFY;
491             case "quicken" : return TRON_COMPILATION_FILTER_QUICKEN;
492             case "space-profile" : return TRON_COMPILATION_FILTER_SPACE_PROFILE;
493             case "space" : return TRON_COMPILATION_FILTER_SPACE;
494             case "speed-profile" : return TRON_COMPILATION_FILTER_SPEED_PROFILE;
495             case "speed" : return TRON_COMPILATION_FILTER_SPEED;
496             case "everything-profile" : return TRON_COMPILATION_FILTER_EVERYTHING_PROFILE;
497             case "everything" : return TRON_COMPILATION_FILTER_EVERYTHING;
498             case "run-from-apk" : return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK;
499             case "run-from-apk-fallback" :
500                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
501             case "run-from-vdex-fallback" :
502                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
503             case "assume-verified-iorap" : return TRON_COMPILATION_FILTER_ASSUMED_VERIFIED_IORAP;
504             case "extract-iorap" : return TRON_COMPILATION_FILTER_EXTRACT_IORAP;
505             case "verify-iorap" : return TRON_COMPILATION_FILTER_VERIFY_IORAP;
506             case "quicken-iorap" : return TRON_COMPILATION_FILTER_QUICKEN_IORAP;
507             case "space-profile-iorap" : return TRON_COMPILATION_FILTER_SPACE_PROFILE_IORAP;
508             case "space-iorap" : return TRON_COMPILATION_FILTER_SPACE_IORAP;
509             case "speed-profile-iorap" : return TRON_COMPILATION_FILTER_SPEED_PROFILE_IORAP;
510             case "speed-iorap" : return TRON_COMPILATION_FILTER_SPEED_IORAP;
511             case "everything-profile-iorap" :
512                 return TRON_COMPILATION_FILTER_EVERYTHING_PROFILE_IORAP;
513             case "everything-iorap" : return TRON_COMPILATION_FILTER_EVERYTHING_IORAP;
514             case "run-from-apk-iorap" : return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_IORAP;
515             case "run-from-apk-fallback-iorap" :
516                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK_IORAP;
517             case "run-from-vdex-fallback-iorap" :
518                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK_IORAP;
519             default: return TRON_COMPILATION_FILTER_UNKNOWN;
520         }
521     }
522 
verifyTronLoggingConstants()523     private static void verifyTronLoggingConstants() {
524         for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
525             String reason = PackageManagerServiceCompilerMapping.REASON_STRINGS[i];
526             int value = getCompilationReasonTronValue(reason);
527             if (value == TRON_COMPILATION_REASON_ERROR
528                     || value == TRON_COMPILATION_REASON_UNKNOWN) {
529                 throw new IllegalArgumentException("Compilation reason not configured for TRON "
530                         + "logging: " + reason);
531             }
532         }
533     }
534 
535     private class ArtManagerInternalImpl extends ArtManagerInternal {
536         private static final String IORAP_DIR = "/data/misc/iorapd";
537         private static final String TAG = "ArtManagerInternalImpl";
538 
539         @Override
getPackageOptimizationInfo( ApplicationInfo info, String abi, String activityName)540         public PackageOptimizationInfo getPackageOptimizationInfo(
541                 ApplicationInfo info, String abi, String activityName) {
542             if (info.packageName.equals(PackageManagerService.PLATFORM_PACKAGE_NAME)) {
543                 // PackageManagerService.PLATFORM_PACKAGE_NAME in this context means that the
544                 // activity is defined in bootclasspath. Currently, we don't have an API to get the
545                 // correct optimization info.
546                 return PackageOptimizationInfo.createWithNoInfo();
547             }
548 
549             String compilationReason;
550             String compilationFilter;
551             try {
552                 String isa = VMRuntime.getInstructionSet(abi);
553                 DexFile.OptimizationInfo optInfo =
554                         DexFile.getDexFileOptimizationInfo(info.getBaseCodePath(), isa);
555                 compilationFilter = optInfo.getStatus();
556                 compilationReason = optInfo.getReason();
557             } catch (FileNotFoundException e) {
558                 Slog.e(TAG, "Could not get optimizations status for " + info.getBaseCodePath(), e);
559                 compilationFilter = "error";
560                 compilationReason = "error";
561             } catch (IllegalArgumentException e) {
562                 Slog.wtf(TAG, "Requested optimization status for " + info.getBaseCodePath()
563                         + " due to an invalid abi " + abi, e);
564                 compilationFilter = "error";
565                 compilationReason = "error";
566             }
567 
568             if (checkIorapCompiledTrace(info.packageName, activityName, info.longVersionCode)) {
569                 compilationFilter = compilationFilter + "-iorap";
570             }
571 
572             int compilationFilterTronValue = getCompilationFilterTronValue(compilationFilter);
573             int compilationReasonTronValue = getCompilationReasonTronValue(compilationReason);
574 
575             return new PackageOptimizationInfo(
576                     compilationFilterTronValue, compilationReasonTronValue);
577         }
578 
579         /*
580          * Checks the existence of IORap compiled trace for an app.
581          *
582          * @return true if the compiled trace exists and the size is greater than 1kb.
583          */
checkIorapCompiledTrace( String packageName, String activityName, long version)584         private boolean checkIorapCompiledTrace(
585                 String packageName, String activityName, long version) {
586             // For example: /data/misc/iorapd/com.google.android.GoogleCamera/
587             // 60092239/com.android.camera.CameraLauncher/compiled_traces/compiled_trace.pb
588             // TODO(b/258223472): Clean up iorap code.
589             Path tracePath = Paths.get(IORAP_DIR,
590                                        packageName,
591                                        Long.toString(version),
592                                        activityName,
593                                        "compiled_traces",
594                                        "compiled_trace.pb");
595             try {
596                 boolean exists =  Files.exists(tracePath);
597                 if (DEBUG) {
598                     Log.d(TAG, tracePath.toString() + (exists? " exists" : " doesn't exist"));
599                 }
600                 if (exists) {
601                     long bytes = Files.size(tracePath);
602                     if (DEBUG) {
603                         Log.d(TAG, tracePath.toString() + " size is " + Long.toString(bytes));
604                     }
605                     return bytes > 0L;
606                 }
607                 return exists;
608             } catch (IOException e) {
609                 Log.d(TAG, e.getMessage());
610                 return false;
611             }
612         }
613     }
614 }
615