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