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