Home | History | Annotate | Download | only in dex
      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.UserIdInt;
     20 import android.app.AppOpsManager;
     21 import android.content.Context;
     22 import android.content.pm.ApplicationInfo;
     23 import android.content.pm.IPackageManager;
     24 import android.content.pm.PackageInfo;
     25 import android.content.pm.PackageManager;
     26 import android.content.pm.PackageParser;
     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.DexMetadataHelper;
     31 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
     32 import android.content.pm.dex.PackageOptimizationInfo;
     33 import android.os.Binder;
     34 import android.os.Build;
     35 import android.os.Handler;
     36 import android.os.ParcelFileDescriptor;
     37 import android.os.Process;
     38 import android.os.RemoteException;
     39 import android.os.SystemProperties;
     40 import android.os.UserHandle;
     41 import android.system.Os;
     42 import android.util.ArrayMap;
     43 import android.util.Log;
     44 import android.util.Slog;
     45 
     46 import com.android.internal.annotations.GuardedBy;
     47 import com.android.internal.os.BackgroundThread;
     48 import com.android.internal.os.RoSystemProperties;
     49 import com.android.internal.util.ArrayUtils;
     50 import com.android.internal.util.Preconditions;
     51 import com.android.server.LocalServices;
     52 import com.android.server.pm.Installer;
     53 import com.android.server.pm.Installer.InstallerException;
     54 import com.android.server.pm.PackageManagerServiceCompilerMapping;
     55 
     56 import dalvik.system.DexFile;
     57 import dalvik.system.VMRuntime;
     58 
     59 import libcore.io.IoUtils;
     60 import libcore.util.NonNull;
     61 import libcore.util.Nullable;
     62 
     63 import java.io.File;
     64 import java.io.FileNotFoundException;
     65 
     66 /**
     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  */
     78 public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
     79     private static final String TAG = "ArtManagerService";
     80     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     81 
     82     // 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 
     88     private final Context mContext;
     89     private final IPackageManager mPackageManager;
     90     private final Object mInstallLock;
     91     @GuardedBy("mInstallLock")
     92     private final Installer mInstaller;
     93 
     94     private final Handler mHandler;
     95 
     96     static {
     97         verifyTronLoggingConstants();
     98     }
     99 
    100     public ArtManagerService(Context context, IPackageManager pm, Installer installer,
    101             Object installLock) {
    102         mContext = context;
    103         mPackageManager = pm;
    104         mInstaller = installer;
    105         mInstallLock = installLock;
    106         mHandler = new Handler(BackgroundThread.getHandler().getLooper());
    107 
    108         LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl());
    109     }
    110 
    111     private boolean checkAndroidPermissions(int callingUid, String callingPackage) {
    112         // 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 
    130     /**
    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 
    168     @Override
    169     public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
    170             @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback,
    171             String callingPackage) {
    172         int callingUid = Binder.getCallingUid();
    173         if (!checkShellPermissions(profileType, packageName, callingUid) &&
    174                 !checkAndroidPermissions(callingUid, callingPackage)) {
    175             try {
    176                 callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
    177             } catch (RemoteException ignored) {
    178             }
    179             return;
    180         }
    181 
    182         // Sanity checks on the arguments.
    183         Preconditions.checkNotNull(callback);
    184 
    185         boolean bootImageProfile = profileType == ArtManager.PROFILE_BOOT_IMAGE;
    186         if (!bootImageProfile) {
    187             Preconditions.checkStringNotEmpty(codePath);
    188             Preconditions.checkStringNotEmpty(packageName);
    189         }
    190 
    191         // Verify that runtime profiling is enabled.
    192         if (!isRuntimeProfilingEnabled(profileType, callingPackage)) {
    193             throw new IllegalStateException("Runtime profiling is not enabled for " + profileType);
    194         }
    195 
    196         if (DEBUG) {
    197             Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath);
    198         }
    199 
    200         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) {
    209         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);
    228         String splitName = null;
    229         String[] splitCodePaths = info.applicationInfo.getSplitCodePaths();
    230         if (!pathFound && (splitCodePaths != null)) {
    231             for (int i = splitCodePaths.length - 1; i >= 0; i--) {
    232                 if (splitCodePaths[i].equals(codePath)) {
    233                     pathFound = true;
    234                     splitName = info.applicationInfo.splitNames[i];
    235                     break;
    236                 }
    237             }
    238         }
    239         if (!pathFound) {
    240             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND);
    241             return;
    242         }
    243 
    244         // All good, create the profile snapshot.
    245         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);
    254         // Destroy the snapshot, we no longer need it.
    255         destroyProfileSnapshot(packageName, ArtManager.getProfileName(splitName));
    256     }
    257 
    258     private void createProfileSnapshot(String packageName, String profileName, String classpath,
    259             int appId, ISnapshotRuntimeProfileCallback callback) {
    260         // Ask the installer to snapshot the profile.
    261         synchronized (mInstallLock) {
    262             try {
    263                 if (!mInstaller.createProfileSnapshot(appId, packageName, profileName, classpath)) {
    264                     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.
    274         File snapshotProfile = ArtManager.getProfileSnapshotFileForName(packageName, profileName);
    275 
    276         ParcelFileDescriptor fd = null;
    277         try {
    278             fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY);
    279             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             }
    287         } catch (FileNotFoundException e) {
    288             Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":"
    289                     + snapshotProfile, e);
    290             postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
    291         }
    292     }
    293 
    294     private void destroyProfileSnapshot(String packageName, String profileName) {
    295         if (DEBUG) {
    296             Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + profileName);
    297         }
    298 
    299         synchronized (mInstallLock) {
    300             try {
    301                 mInstaller.destroyProfileSnapshot(packageName, profileName);
    302             } catch (InstallerException e) {
    303                 Slog.e(TAG, "Failed to destroy profile snapshot for " +
    304                     packageName + ":" + profileName, e);
    305             }
    306         }
    307     }
    308 
    309     @Override
    310     public boolean isRuntimeProfilingEnabled(@ProfileType int profileType, String callingPackage) {
    311         int callingUid = Binder.getCallingUid();
    312         if (callingUid != Process.SHELL_UID && !checkAndroidPermissions(callingUid, callingPackage)) {
    313             return false;
    314         }
    315 
    316         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);
    339     }
    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) {
    347         if (DEBUG) {
    348             Slog.d(TAG, "Failed to snapshot profile for " + packageName + " with error: " +
    349                     errCode);
    350         }
    351         mHandler.post(() -> {
    352             try {
    353                 callback.onError(errCode);
    354             } catch (Exception e) {
    355                 Slog.w(TAG, "Failed to callback after profile snapshot for " + packageName, e);
    356             }
    357         });
    358     }
    359 
    360     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 {
    367                 // 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) {
    378                 Slog.w(TAG,
    379                         "Failed to call onSuccess after profile snapshot for " + packageName, e);
    380             } finally {
    381                 IoUtils.closeQuietly(fd);
    382             }
    383         });
    384     }
    385 
    386     /**
    387      * 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);
    394         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         }
    402         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     /**
    424      * 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     /**
    433      * 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     /**
    467      * 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     }
    484 
    485     // 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;
    522 
    523     /**
    524      * Convert the compilation reason to an int suitable to be logged to TRON.
    525      */
    526     private static int getCompilationReasonTronValue(String compilationReason) {
    527         switch (compilationReason) {
    528             case "unknown" : return TRON_COMPILATION_REASON_UNKNOWN;
    529             case "error" : return TRON_COMPILATION_REASON_ERROR;
    530             case "first-boot" : return TRON_COMPILATION_REASON_FIRST_BOOT;
    531             case "boot" : return TRON_COMPILATION_REASON_BOOT;
    532             case "install" : return TRON_COMPILATION_REASON_INSTALL;
    533             case "bg-dexopt" : return TRON_COMPILATION_REASON_BG_DEXOPT;
    534             case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA;
    535             case "inactive" : return TRON_COMPILATION_REASON_INACTIVE;
    536             case "shared" : return TRON_COMPILATION_REASON_SHARED;
    537             default: return TRON_COMPILATION_REASON_UNKNOWN;
    538         }
    539     }
    540 
    541     /**
    542      * Convert the compilation filter to an int suitable to be logged to TRON.
    543      */
    544     private static int getCompilationFilterTronValue(String compilationFilter) {
    545         switch (compilationFilter) {
    546             case "error" : return TRON_COMPILATION_FILTER_ERROR;
    547             case "unknown" : return TRON_COMPILATION_FILTER_UNKNOWN;
    548             case "assume-verified" : return TRON_COMPILATION_FILTER_ASSUMED_VERIFIED;
    549             case "extract" : return TRON_COMPILATION_FILTER_EXTRACT;
    550             case "verify" : return TRON_COMPILATION_FILTER_VERIFY;
    551             case "quicken" : return TRON_COMPILATION_FILTER_QUICKEN;
    552             case "space-profile" : return TRON_COMPILATION_FILTER_SPACE_PROFILE;
    553             case "space" : return TRON_COMPILATION_FILTER_SPACE;
    554             case "speed-profile" : return TRON_COMPILATION_FILTER_SPEED_PROFILE;
    555             case "speed" : return TRON_COMPILATION_FILTER_SPEED;
    556             case "everything-profile" : return TRON_COMPILATION_FILTER_EVERYTHING_PROFILE;
    557             case "everything" : return TRON_COMPILATION_FILTER_EVERYTHING;
    558             case "run-from-apk" : return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK;
    559             case "run-from-apk-fallback" :
    560                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
    561             case "run-from-vdex-fallback" :
    562                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
    563             default: return TRON_COMPILATION_FILTER_UNKNOWN;
    564         }
    565     }
    566 
    567     private static void verifyTronLoggingConstants() {
    568         for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
    569             String reason = PackageManagerServiceCompilerMapping.REASON_STRINGS[i];
    570             int value = getCompilationReasonTronValue(reason);
    571             if (value == TRON_COMPILATION_REASON_ERROR
    572                     || value == TRON_COMPILATION_REASON_UNKNOWN) {
    573                 throw new IllegalArgumentException("Compilation reason not configured for TRON "
    574                         + "logging: " + reason);
    575             }
    576         }
    577     }
    578 
    579     private class ArtManagerInternalImpl extends ArtManagerInternal {
    580         @Override
    581         public PackageOptimizationInfo getPackageOptimizationInfo(
    582                 ApplicationInfo info, String abi) {
    583             String compilationReason;
    584             String compilationFilter;
    585             try {
    586                 String isa = VMRuntime.getInstructionSet(abi);
    587                 DexFile.OptimizationInfo optInfo =
    588                         DexFile.getDexFileOptimizationInfo(info.getBaseCodePath(), isa);
    589                 compilationFilter = optInfo.getStatus();
    590                 compilationReason = optInfo.getReason();
    591             } catch (FileNotFoundException e) {
    592                 Slog.e(TAG, "Could not get optimizations status for " + info.getBaseCodePath(), e);
    593                 compilationFilter = "error";
    594                 compilationReason = "error";
    595             } catch (IllegalArgumentException e) {
    596                 Slog.wtf(TAG, "Requested optimization status for " + info.getBaseCodePath()
    597                         + " due to an invalid abi " + abi, e);
    598                 compilationFilter = "error";
    599                 compilationReason = "error";
    600             }
    601 
    602             int compilationFilterTronValue = getCompilationFilterTronValue(compilationFilter);
    603             int compilationReasonTronValue = getCompilationReasonTronValue(compilationReason);
    604 
    605             return new PackageOptimizationInfo(
    606                     compilationFilterTronValue, compilationReasonTronValue);
    607         }
    608     }
    609 }
    610