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.PackageParser; 29 import android.content.pm.dex.ArtManager; 30 import android.content.pm.dex.ArtManager.ProfileType; 31 import android.content.pm.dex.ArtManagerInternal; 32 import android.content.pm.dex.DexMetadataHelper; 33 import android.content.pm.dex.ISnapshotRuntimeProfileCallback; 34 import android.content.pm.dex.PackageOptimizationInfo; 35 import android.os.Binder; 36 import android.os.Build; 37 import android.os.Handler; 38 import android.os.ParcelFileDescriptor; 39 import android.os.Process; 40 import android.os.RemoteException; 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.annotations.GuardedBy; 49 import com.android.internal.os.BackgroundThread; 50 import com.android.internal.os.RoSystemProperties; 51 import com.android.internal.util.ArrayUtils; 52 import com.android.internal.util.Preconditions; 53 import com.android.server.LocalServices; 54 import com.android.server.pm.Installer; 55 import com.android.server.pm.Installer.InstallerException; 56 import com.android.server.pm.PackageManagerServiceCompilerMapping; 57 58 import dalvik.system.DexFile; 59 import dalvik.system.VMRuntime; 60 61 import libcore.io.IoUtils; 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 { verifyTronLoggingConstants()97 verifyTronLoggingConstants(); 98 } 99 ArtManagerService(Context context, IPackageManager pm, Installer installer, Object installLock)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 checkAndroidPermissions(int callingUid, String callingPackage)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 */ checkShellPermissions(@rofileType int profileType, String packageName, int callingUid)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 snapshotRuntimeProfile(@rofileType int profileType, @Nullable String packageName, @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback, String callingPackage)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 snapshotAppProfile(String packageName, String codePath, ISnapshotRuntimeProfileCallback callback)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 createProfileSnapshot(String packageName, String profileName, String classpath, int appId, ISnapshotRuntimeProfileCallback callback)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 destroyProfileSnapshot(String packageName, String profileName)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 isRuntimeProfilingEnabled(@rofileType int profileType, String callingPackage)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 snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback)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 */ postError(ISnapshotRuntimeProfileCallback callback, String packageName, int errCode)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 postSuccess(String packageName, ParcelFileDescriptor fd, ISnapshotRuntimeProfileCallback callback)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 */ prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user, boolean updateReferenceProfileContent)392 public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user, 393 boolean updateReferenceProfileContent) { 394 final int appId = UserHandle.getAppId(pkg.applicationInfo.uid); 395 if (user < 0) { 396 Slog.wtf(TAG, "Invalid user id: " + user); 397 return; 398 } 399 if (appId < 0) { 400 Slog.wtf(TAG, "Invalid app id: " + appId); 401 return; 402 } 403 try { 404 ArrayMap<String, String> codePathsProfileNames = getPackageProfileNames(pkg); 405 for (int i = codePathsProfileNames.size() - 1; i >= 0; i--) { 406 String codePath = codePathsProfileNames.keyAt(i); 407 String profileName = codePathsProfileNames.valueAt(i); 408 String dexMetadataPath = null; 409 // Passing the dex metadata file to the prepare method will update the reference 410 // profile content. As such, we look for the dex metadata file only if we need to 411 // perform an update. 412 if (updateReferenceProfileContent) { 413 File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath)); 414 dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath(); 415 } 416 synchronized (mInstaller) { 417 boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId, 418 profileName, codePath, dexMetadataPath); 419 if (!result) { 420 Slog.e(TAG, "Failed to prepare profile for " + 421 pkg.packageName + ":" + codePath); 422 } 423 } 424 } 425 } catch (InstallerException e) { 426 Slog.e(TAG, "Failed to prepare profile for " + pkg.packageName, e); 427 } 428 } 429 430 /** 431 * Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}. 432 */ prepareAppProfiles(PackageParser.Package pkg, int[] user, boolean updateReferenceProfileContent)433 public void prepareAppProfiles(PackageParser.Package pkg, int[] user, 434 boolean updateReferenceProfileContent) { 435 for (int i = 0; i < user.length; i++) { 436 prepareAppProfiles(pkg, user[i], updateReferenceProfileContent); 437 } 438 } 439 440 /** 441 * Clear the profiles for the given package. 442 */ clearAppProfiles(PackageParser.Package pkg)443 public void clearAppProfiles(PackageParser.Package pkg) { 444 try { 445 ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg); 446 for (int i = packageProfileNames.size() - 1; i >= 0; i--) { 447 String profileName = packageProfileNames.valueAt(i); 448 mInstaller.clearAppProfiles(pkg.packageName, profileName); 449 } 450 } catch (InstallerException e) { 451 Slog.w(TAG, String.valueOf(e)); 452 } 453 } 454 455 /** 456 * Dumps the profiles for the given package. 457 */ dumpProfiles(PackageParser.Package pkg)458 public void dumpProfiles(PackageParser.Package pkg) { 459 final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); 460 try { 461 ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg); 462 for (int i = packageProfileNames.size() - 1; i >= 0; i--) { 463 String codePath = packageProfileNames.keyAt(i); 464 String profileName = packageProfileNames.valueAt(i); 465 synchronized (mInstallLock) { 466 mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath); 467 } 468 } 469 } catch (InstallerException e) { 470 Slog.w(TAG, "Failed to dump profiles", e); 471 } 472 } 473 474 /** 475 * Compile layout resources in a given package. 476 */ compileLayouts(PackageParser.Package pkg)477 public boolean compileLayouts(PackageParser.Package pkg) { 478 try { 479 final String packageName = pkg.packageName; 480 final String apkPath = pkg.baseCodePath; 481 final ApplicationInfo appInfo = pkg.applicationInfo; 482 final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex"; 483 if (appInfo.isPrivilegedApp() || appInfo.isEmbeddedDexUsed() 484 || appInfo.isDefaultToDeviceProtectedStorage()) { 485 // Privileged apps prefer to load trusted code so they don't use compiled views. 486 // If the app is not privileged but prefers code integrity, also avoid compiling 487 // views. 488 // Also disable the view compiler for protected storage apps since there are 489 // selinux permissions required for writing to user_de. 490 return false; 491 } 492 Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath + 493 ") to " + outDexFile); 494 long callingId = Binder.clearCallingIdentity(); 495 try { 496 synchronized (mInstallLock) { 497 return mInstaller.compileLayouts(apkPath, packageName, outDexFile, 498 appInfo.uid); 499 } 500 } finally { 501 Binder.restoreCallingIdentity(callingId); 502 } 503 } 504 catch (Throwable e) { 505 Log.e("PackageManager", "Failed to compile layouts", e); 506 return false; 507 } 508 } 509 510 /** 511 * Build the profiles names for all the package code paths (excluding resource only paths). 512 * Return the map [code path -> profile name]. 513 */ getPackageProfileNames(PackageParser.Package pkg)514 private ArrayMap<String, String> getPackageProfileNames(PackageParser.Package pkg) { 515 ArrayMap<String, String> result = new ArrayMap<>(); 516 if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { 517 result.put(pkg.baseCodePath, ArtManager.getProfileName(null)); 518 } 519 if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { 520 for (int i = 0; i < pkg.splitCodePaths.length; i++) { 521 if ((pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { 522 result.put(pkg.splitCodePaths[i], ArtManager.getProfileName(pkg.splitNames[i])); 523 } 524 } 525 } 526 return result; 527 } 528 529 // Constants used for logging compilation filter to TRON. 530 // DO NOT CHANGE existing values. 531 // 532 // NOTE: '-1' value is reserved for the case where we cannot produce a valid 533 // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the 534 // ActivityMetricsLoggers. 535 private static final int TRON_COMPILATION_FILTER_ERROR = 0; 536 private static final int TRON_COMPILATION_FILTER_UNKNOWN = 1; 537 private static final int TRON_COMPILATION_FILTER_ASSUMED_VERIFIED = 2; 538 private static final int TRON_COMPILATION_FILTER_EXTRACT = 3; 539 private static final int TRON_COMPILATION_FILTER_VERIFY = 4; 540 private static final int TRON_COMPILATION_FILTER_QUICKEN = 5; 541 private static final int TRON_COMPILATION_FILTER_SPACE_PROFILE = 6; 542 private static final int TRON_COMPILATION_FILTER_SPACE = 7; 543 private static final int TRON_COMPILATION_FILTER_SPEED_PROFILE = 8; 544 private static final int TRON_COMPILATION_FILTER_SPEED = 9; 545 private static final int TRON_COMPILATION_FILTER_EVERYTHING_PROFILE = 10; 546 private static final int TRON_COMPILATION_FILTER_EVERYTHING = 11; 547 private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK = 12; 548 private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK = 13; 549 private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK = 14; 550 551 // Constants used for logging compilation reason to TRON. 552 // DO NOT CHANGE existing values. 553 // 554 // NOTE: '-1' value is reserved for the case where we cannot produce a valid 555 // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the 556 // ActivityMetricsLoggers. 557 private static final int TRON_COMPILATION_REASON_ERROR = 0; 558 private static final int TRON_COMPILATION_REASON_UNKNOWN = 1; 559 private static final int TRON_COMPILATION_REASON_FIRST_BOOT = 2; 560 private static final int TRON_COMPILATION_REASON_BOOT = 3; 561 private static final int TRON_COMPILATION_REASON_INSTALL = 4; 562 private static final int TRON_COMPILATION_REASON_BG_DEXOPT = 5; 563 private static final int TRON_COMPILATION_REASON_AB_OTA = 6; 564 private static final int TRON_COMPILATION_REASON_INACTIVE = 7; 565 private static final int TRON_COMPILATION_REASON_SHARED = 8; 566 private static final int TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA = 9; 567 568 // The annotation to add as a suffix to the compilation reason when dexopt was 569 // performed with dex metadata. 570 public static final String DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION = "-dm"; 571 572 /** 573 * Convert the compilation reason to an int suitable to be logged to TRON. 574 */ getCompilationReasonTronValue(String compilationReason)575 private static int getCompilationReasonTronValue(String compilationReason) { 576 switch (compilationReason) { 577 case "unknown" : return TRON_COMPILATION_REASON_UNKNOWN; 578 case "error" : return TRON_COMPILATION_REASON_ERROR; 579 case "first-boot" : return TRON_COMPILATION_REASON_FIRST_BOOT; 580 case "boot" : return TRON_COMPILATION_REASON_BOOT; 581 case "install" : return TRON_COMPILATION_REASON_INSTALL; 582 case "bg-dexopt" : return TRON_COMPILATION_REASON_BG_DEXOPT; 583 case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA; 584 case "inactive" : return TRON_COMPILATION_REASON_INACTIVE; 585 case "shared" : return TRON_COMPILATION_REASON_SHARED; 586 // This is a special marker for dex metadata installation that does not 587 // have an equivalent as a system property. 588 case "install" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : 589 return TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA; 590 default: return TRON_COMPILATION_REASON_UNKNOWN; 591 } 592 } 593 594 /** 595 * Convert the compilation filter to an int suitable to be logged to TRON. 596 */ getCompilationFilterTronValue(String compilationFilter)597 private static int getCompilationFilterTronValue(String compilationFilter) { 598 switch (compilationFilter) { 599 case "error" : return TRON_COMPILATION_FILTER_ERROR; 600 case "unknown" : return TRON_COMPILATION_FILTER_UNKNOWN; 601 case "assume-verified" : return TRON_COMPILATION_FILTER_ASSUMED_VERIFIED; 602 case "extract" : return TRON_COMPILATION_FILTER_EXTRACT; 603 case "verify" : return TRON_COMPILATION_FILTER_VERIFY; 604 case "quicken" : return TRON_COMPILATION_FILTER_QUICKEN; 605 case "space-profile" : return TRON_COMPILATION_FILTER_SPACE_PROFILE; 606 case "space" : return TRON_COMPILATION_FILTER_SPACE; 607 case "speed-profile" : return TRON_COMPILATION_FILTER_SPEED_PROFILE; 608 case "speed" : return TRON_COMPILATION_FILTER_SPEED; 609 case "everything-profile" : return TRON_COMPILATION_FILTER_EVERYTHING_PROFILE; 610 case "everything" : return TRON_COMPILATION_FILTER_EVERYTHING; 611 case "run-from-apk" : return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK; 612 case "run-from-apk-fallback" : 613 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK; 614 case "run-from-vdex-fallback" : 615 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK; 616 default: return TRON_COMPILATION_FILTER_UNKNOWN; 617 } 618 } 619 verifyTronLoggingConstants()620 private static void verifyTronLoggingConstants() { 621 for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) { 622 String reason = PackageManagerServiceCompilerMapping.REASON_STRINGS[i]; 623 int value = getCompilationReasonTronValue(reason); 624 if (value == TRON_COMPILATION_REASON_ERROR 625 || value == TRON_COMPILATION_REASON_UNKNOWN) { 626 throw new IllegalArgumentException("Compilation reason not configured for TRON " 627 + "logging: " + reason); 628 } 629 } 630 } 631 632 private class ArtManagerInternalImpl extends ArtManagerInternal { 633 @Override getPackageOptimizationInfo( ApplicationInfo info, String abi)634 public PackageOptimizationInfo getPackageOptimizationInfo( 635 ApplicationInfo info, String abi) { 636 String compilationReason; 637 String compilationFilter; 638 try { 639 String isa = VMRuntime.getInstructionSet(abi); 640 DexFile.OptimizationInfo optInfo = 641 DexFile.getDexFileOptimizationInfo(info.getBaseCodePath(), isa); 642 compilationFilter = optInfo.getStatus(); 643 compilationReason = optInfo.getReason(); 644 } catch (FileNotFoundException e) { 645 Slog.e(TAG, "Could not get optimizations status for " + info.getBaseCodePath(), e); 646 compilationFilter = "error"; 647 compilationReason = "error"; 648 } catch (IllegalArgumentException e) { 649 Slog.wtf(TAG, "Requested optimization status for " + info.getBaseCodePath() 650 + " due to an invalid abi " + abi, e); 651 compilationFilter = "error"; 652 compilationReason = "error"; 653 } 654 655 int compilationFilterTronValue = getCompilationFilterTronValue(compilationFilter); 656 int compilationReasonTronValue = getCompilationReasonTronValue(compilationReason); 657 658 return new PackageOptimizationInfo( 659 compilationFilterTronValue, compilationReasonTronValue); 660 } 661 } 662 } 663