1 /* 2 * Copyright (C) 2008 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; 18 19 import static com.android.server.pm.DexOptHelper.useArtService; 20 21 import android.annotation.AppIdInt; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.UserIdInt; 25 import android.content.Context; 26 import android.content.pm.PackageStats; 27 import android.os.Build; 28 import android.os.CreateAppDataArgs; 29 import android.os.CreateAppDataResult; 30 import android.os.IBinder; 31 import android.os.IInstalld; 32 import android.os.ReconcileSdkDataArgs; 33 import android.os.RemoteException; 34 import android.os.ServiceManager; 35 import android.os.storage.CrateMetadata; 36 import android.text.format.DateUtils; 37 import android.util.Slog; 38 39 import com.android.internal.os.BackgroundThread; 40 import com.android.server.SystemService; 41 42 import dalvik.system.BlockGuard; 43 import dalvik.system.VMRuntime; 44 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 import java.util.List; 48 import java.util.concurrent.CompletableFuture; 49 import java.util.concurrent.CountDownLatch; 50 import java.util.concurrent.TimeUnit; 51 52 public class Installer extends SystemService { 53 private static final String TAG = "Installer"; 54 55 /* *************************************************************************** 56 * IMPORTANT: These values are passed to native code. Keep them in sync with 57 * frameworks/native/cmds/installd/installd_constants.h 58 * **************************************************************************/ 59 /** Application should be visible to everyone */ 60 public static final int DEXOPT_PUBLIC = 1 << 1; 61 /** Application wants to allow debugging of its code */ 62 public static final int DEXOPT_DEBUGGABLE = 1 << 2; 63 /** The system boot has finished */ 64 public static final int DEXOPT_BOOTCOMPLETE = 1 << 3; 65 /** Hint that the dexopt type is profile-guided. */ 66 public static final int DEXOPT_PROFILE_GUIDED = 1 << 4; 67 /** The compilation is for a secondary dex file. */ 68 public static final int DEXOPT_SECONDARY_DEX = 1 << 5; 69 /** Ignore the result of dexoptNeeded and force compilation. */ 70 public static final int DEXOPT_FORCE = 1 << 6; 71 /** Indicates that the dex file passed to dexopt in on CE storage. */ 72 public static final int DEXOPT_STORAGE_CE = 1 << 7; 73 /** Indicates that the dex file passed to dexopt in on DE storage. */ 74 public static final int DEXOPT_STORAGE_DE = 1 << 8; 75 /** Indicates that dexopt is invoked from the background service. */ 76 public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9; 77 /** Indicates that dexopt should restrict access to private APIs. */ 78 public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10; 79 /** Indicates that dexopt should convert to CompactDex. */ 80 public static final int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11; 81 /** Indicates that dexopt should generate an app image */ 82 public static final int DEXOPT_GENERATE_APP_IMAGE = 1 << 12; 83 /** Indicates that dexopt may be run with different performance / priority tuned for restore */ 84 public static final int DEXOPT_FOR_RESTORE = 1 << 13; // TODO(b/135202722): remove 85 86 /** The result of the profile analysis indicating that the app should be optimized. */ 87 public static final int PROFILE_ANALYSIS_OPTIMIZE = 1; 88 /** The result of the profile analysis indicating that the app should not be optimized. */ 89 public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA = 2; 90 /** 91 * The result of the profile analysis indicating that the app should not be optimized because 92 * the profiles are empty. 93 */ 94 public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3; 95 96 /** 97 * The results of {@code getOdexVisibility}. See 98 * {@link #getOdexVisibility(String, String, String)} for details. 99 */ 100 public static final int ODEX_NOT_FOUND = 0; 101 public static final int ODEX_IS_PUBLIC = 1; 102 public static final int ODEX_IS_PRIVATE = 2; 103 104 105 public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE; 106 public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE; 107 public static final int FLAG_STORAGE_EXTERNAL = IInstalld.FLAG_STORAGE_EXTERNAL; 108 public static final int FLAG_STORAGE_SDK = IInstalld.FLAG_STORAGE_SDK; 109 110 public static final int FLAG_CLEAR_CACHE_ONLY = IInstalld.FLAG_CLEAR_CACHE_ONLY; 111 public static final int FLAG_CLEAR_CODE_CACHE_ONLY = IInstalld.FLAG_CLEAR_CODE_CACHE_ONLY; 112 113 public static final int FLAG_FREE_CACHE_V2 = IInstalld.FLAG_FREE_CACHE_V2; 114 public static final int FLAG_FREE_CACHE_V2_DEFY_QUOTA = IInstalld.FLAG_FREE_CACHE_V2_DEFY_QUOTA; 115 public static final int FLAG_FREE_CACHE_NOOP = IInstalld.FLAG_FREE_CACHE_NOOP; 116 public static final int FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES = 117 IInstalld.FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES; 118 119 public static final int FLAG_USE_QUOTA = IInstalld.FLAG_USE_QUOTA; 120 public static final int FLAG_FORCE = IInstalld.FLAG_FORCE; 121 122 public static final int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES = 123 IInstalld.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES; 124 125 private static final long CONNECT_RETRY_DELAY_MS = DateUtils.SECOND_IN_MILLIS; 126 private static final long CONNECT_WAIT_MS = 10 * DateUtils.SECOND_IN_MILLIS; 127 128 private final boolean mIsolated; 129 private volatile boolean mDeferSetFirstBoot; 130 private volatile IInstalld mInstalld = null; 131 private volatile CountDownLatch mInstalldLatch = new CountDownLatch(1); 132 private volatile Object mWarnIfHeld; 133 Installer(Context context)134 public Installer(Context context) { 135 this(context, false); 136 } 137 138 /** 139 * @param isolated Make the installer isolated. See {@link isIsolated}. 140 */ Installer(Context context, boolean isolated)141 public Installer(Context context, boolean isolated) { 142 super(context); 143 mIsolated = isolated; 144 } 145 146 /** 147 * Yell loudly if someone tries making future calls while holding a lock on 148 * the given object. 149 */ setWarnIfHeld(Object warnIfHeld)150 public void setWarnIfHeld(Object warnIfHeld) { 151 mWarnIfHeld = warnIfHeld; 152 } 153 154 /** 155 * Returns true if the installer is isolated, i.e. if this object should <em>not</em> connect to 156 * the real {@code installd}. All remote calls will be ignored unless you extend this class and 157 * intercept them. 158 */ isIsolated()159 public boolean isIsolated() { 160 return mIsolated; 161 } 162 163 @Override onStart()164 public void onStart() { 165 if (mIsolated) { 166 mInstalld = null; 167 mInstalldLatch.countDown(); 168 } else { 169 connect(); 170 } 171 } 172 connect()173 private void connect() { 174 IBinder binder = ServiceManager.getService("installd"); 175 if (binder != null) { 176 try { 177 binder.linkToDeath(() -> { 178 Slog.w(TAG, "installd died; reconnecting"); 179 mInstalldLatch = new CountDownLatch(1); 180 connect(); 181 }, 0); 182 } catch (RemoteException e) { 183 binder = null; 184 } 185 } 186 187 if (binder != null) { 188 IInstalld installd = IInstalld.Stub.asInterface(binder); 189 mInstalld = installd; 190 mInstalldLatch.countDown(); 191 try { 192 invalidateMounts(); 193 executeDeferredActions(); 194 } catch (InstallerException ignored) { 195 } 196 } else { 197 Slog.w(TAG, "installd not found; trying again"); 198 BackgroundThread.getHandler().postDelayed(this::connect, CONNECT_RETRY_DELAY_MS); 199 } 200 } 201 202 /** 203 * Perform any deferred actions on mInstalld while the connection could not be made. 204 */ executeDeferredActions()205 private void executeDeferredActions() throws InstallerException { 206 if (mDeferSetFirstBoot) { 207 setFirstBoot(); 208 } 209 } 210 211 /** 212 * Do several pre-flight checks before making a remote call. 213 * 214 * @return if the remote call should continue. 215 */ checkBeforeRemote()216 private boolean checkBeforeRemote() throws InstallerException { 217 if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) { 218 Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" 219 + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable()); 220 } 221 if (mIsolated) { 222 Slog.i(TAG, "Ignoring request because this installer is isolated"); 223 return false; 224 } 225 226 try { 227 if (!mInstalldLatch.await(CONNECT_WAIT_MS, TimeUnit.MILLISECONDS)) { 228 throw new InstallerException("time out waiting for the installer to be ready"); 229 } 230 } catch (InterruptedException e) { 231 // Do nothing. 232 } 233 234 return true; 235 } 236 237 // We explicitly do NOT set previousAppId because the default value should always be 0. 238 // Manually override previousAppId after building CreateAppDataArgs for specific behaviors. buildCreateAppDataArgs(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion, boolean usesSdk)239 static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName, 240 int userId, int flags, int appId, String seInfo, int targetSdkVersion, 241 boolean usesSdk) { 242 final CreateAppDataArgs args = new CreateAppDataArgs(); 243 args.uuid = uuid; 244 args.packageName = packageName; 245 args.userId = userId; 246 args.flags = flags; 247 if (usesSdk) { 248 args.flags |= FLAG_STORAGE_SDK; 249 } 250 args.appId = appId; 251 args.seInfo = seInfo; 252 args.targetSdkVersion = targetSdkVersion; 253 return args; 254 } 255 buildPlaceholderCreateAppDataResult()256 private static CreateAppDataResult buildPlaceholderCreateAppDataResult() { 257 final CreateAppDataResult result = new CreateAppDataResult(); 258 result.ceDataInode = -1; 259 result.exceptionCode = 0; 260 result.exceptionMessage = null; 261 return result; 262 } 263 buildReconcileSdkDataArgs(String uuid, String packageName, List<String> subDirNames, int userId, int appId, String seInfo, int flags)264 static ReconcileSdkDataArgs buildReconcileSdkDataArgs(String uuid, String packageName, 265 List<String> subDirNames, int userId, int appId, 266 String seInfo, int flags) { 267 final ReconcileSdkDataArgs args = new ReconcileSdkDataArgs(); 268 args.uuid = uuid; 269 args.packageName = packageName; 270 args.subDirNames = subDirNames; 271 args.userId = userId; 272 args.appId = appId; 273 args.previousAppId = 0; 274 args.seInfo = seInfo; 275 args.flags = flags; 276 return args; 277 } 278 createAppData(@onNull CreateAppDataArgs args)279 public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args) 280 throws InstallerException { 281 if (!checkBeforeRemote()) { 282 return buildPlaceholderCreateAppDataResult(); 283 } 284 // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088) 285 args.previousAppId = 0; 286 try { 287 return mInstalld.createAppData(args); 288 } catch (Exception e) { 289 throw InstallerException.from(e); 290 } 291 } 292 createAppDataBatched(@onNull CreateAppDataArgs[] args)293 public @NonNull CreateAppDataResult[] createAppDataBatched(@NonNull CreateAppDataArgs[] args) 294 throws InstallerException { 295 if (!checkBeforeRemote()) { 296 final CreateAppDataResult[] results = new CreateAppDataResult[args.length]; 297 Arrays.fill(results, buildPlaceholderCreateAppDataResult()); 298 return results; 299 } 300 // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088) 301 for (final CreateAppDataArgs arg : args) { 302 arg.previousAppId = 0; 303 } 304 try { 305 return mInstalld.createAppDataBatched(args); 306 } catch (Exception e) { 307 throw InstallerException.from(e); 308 } 309 } 310 reconcileSdkData(@onNull ReconcileSdkDataArgs args)311 void reconcileSdkData(@NonNull ReconcileSdkDataArgs args) 312 throws InstallerException { 313 if (!checkBeforeRemote()) { 314 return; 315 } 316 try { 317 mInstalld.reconcileSdkData(args); 318 } catch (Exception e) { 319 throw InstallerException.from(e); 320 } 321 } 322 323 /** 324 * Sets in Installd that it is first boot after data wipe 325 */ setFirstBoot()326 public void setFirstBoot() throws InstallerException { 327 if (!checkBeforeRemote()) { 328 return; 329 } 330 try { 331 // mInstalld might be null if the connection could not be established. 332 if (mInstalld != null) { 333 mInstalld.setFirstBoot(); 334 } else { 335 // if it is null while trying to set the first boot, set a flag to try and set the 336 // first boot when the connection is eventually established 337 mDeferSetFirstBoot = true; 338 } 339 } catch (Exception e) { 340 throw InstallerException.from(e); 341 } 342 } 343 344 /** 345 * Class that collects multiple {@code installd} operations together in an 346 * attempt to more efficiently execute them in bulk. 347 * <p> 348 * Instead of returning results immediately, {@link CompletableFuture} 349 * instances are returned which can be used to chain follow-up work for each 350 * request. 351 * <p> 352 * The creator of this object <em>must</em> invoke {@link #execute()} 353 * exactly once to begin execution of all pending operations. Once execution 354 * has been kicked off, no additional events can be enqueued into this 355 * instance, but multiple instances can safely exist in parallel. 356 */ 357 public static class Batch { 358 private static final int CREATE_APP_DATA_BATCH_SIZE = 256; 359 360 private boolean mExecuted; 361 362 private final List<CreateAppDataArgs> mArgs = new ArrayList<>(); 363 private final List<CompletableFuture<Long>> mFutures = new ArrayList<>(); 364 365 /** 366 * Enqueue the given {@code installd} operation to be executed in the 367 * future when {@link #execute(Installer)} is invoked. 368 * <p> 369 * Callers of this method are not required to hold a monitor lock on an 370 * {@link Installer} object. 371 */ 372 @NonNull createAppData(CreateAppDataArgs args)373 public synchronized CompletableFuture<Long> createAppData(CreateAppDataArgs args) { 374 if (mExecuted) { 375 throw new IllegalStateException(); 376 } 377 final CompletableFuture<Long> future = new CompletableFuture<>(); 378 mArgs.add(args); 379 mFutures.add(future); 380 return future; 381 } 382 383 /** 384 * Execute all pending {@code installd} operations that have been 385 * collected by this batch in a blocking fashion. 386 * <p> 387 * Callers of this method <em>must</em> hold a monitor lock on the given 388 * {@link Installer} object. 389 */ execute(@onNull Installer installer)390 public synchronized void execute(@NonNull Installer installer) throws InstallerException { 391 if (mExecuted) throw new IllegalStateException(); 392 mExecuted = true; 393 394 final int size = mArgs.size(); 395 for (int i = 0; i < size; i += CREATE_APP_DATA_BATCH_SIZE) { 396 final CreateAppDataArgs[] args = new CreateAppDataArgs[Math.min(size - i, 397 CREATE_APP_DATA_BATCH_SIZE)]; 398 for (int j = 0; j < args.length; j++) { 399 args[j] = mArgs.get(i + j); 400 } 401 final CreateAppDataResult[] results = installer.createAppDataBatched(args); 402 for (int j = 0; j < args.length; j++) { 403 final CreateAppDataResult result = results[j]; 404 final CompletableFuture<Long> future = mFutures.get(i + j); 405 if (result.exceptionCode == 0) { 406 future.complete(result.ceDataInode); 407 } else { 408 future.completeExceptionally( 409 new InstallerException(result.exceptionMessage)); 410 } 411 } 412 } 413 } 414 } 415 restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo)416 public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, 417 String seInfo) throws InstallerException { 418 if (!checkBeforeRemote()) return; 419 try { 420 mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo); 421 } catch (Exception e) { 422 throw InstallerException.from(e); 423 } 424 } 425 migrateAppData(String uuid, String packageName, int userId, int flags)426 public void migrateAppData(String uuid, String packageName, int userId, int flags) 427 throws InstallerException { 428 if (!checkBeforeRemote()) return; 429 try { 430 mInstalld.migrateAppData(uuid, packageName, userId, flags); 431 } catch (Exception e) { 432 throw InstallerException.from(e); 433 } 434 } 435 clearAppData(String uuid, String packageName, int userId, int flags, long ceDataInode)436 public void clearAppData(String uuid, String packageName, int userId, int flags, 437 long ceDataInode) throws InstallerException { 438 if (!checkBeforeRemote()) return; 439 try { 440 mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode); 441 } catch (Exception e) { 442 throw InstallerException.from(e); 443 } 444 } 445 destroyAppData(String uuid, String packageName, int userId, int flags, long ceDataInode)446 public void destroyAppData(String uuid, String packageName, int userId, int flags, 447 long ceDataInode) throws InstallerException { 448 if (!checkBeforeRemote()) return; 449 try { 450 mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode); 451 } catch (Exception e) { 452 throw InstallerException.from(e); 453 } 454 } 455 fixupAppData(String uuid, int flags)456 public void fixupAppData(String uuid, int flags) throws InstallerException { 457 if (!checkBeforeRemote()) return; 458 try { 459 mInstalld.fixupAppData(uuid, flags); 460 } catch (Exception e) { 461 throw InstallerException.from(e); 462 } 463 } 464 465 /** 466 * Remove all invalid dirs under app data folder. 467 * All dirs are supposed to be valid file and package names. 468 */ cleanupInvalidPackageDirs(String uuid, int userId, int flags)469 public void cleanupInvalidPackageDirs(String uuid, int userId, int flags) 470 throws InstallerException { 471 if (!checkBeforeRemote()) return; 472 try { 473 mInstalld.cleanupInvalidPackageDirs(uuid, userId, flags); 474 } catch (Exception e) { 475 throw InstallerException.from(e); 476 } 477 } 478 moveCompleteApp(String fromUuid, String toUuid, String packageName, int appId, String seInfo, int targetSdkVersion, String fromCodePath)479 public void moveCompleteApp(String fromUuid, String toUuid, String packageName, 480 int appId, String seInfo, int targetSdkVersion, 481 String fromCodePath) throws InstallerException { 482 if (!checkBeforeRemote()) return; 483 try { 484 mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, appId, seInfo, 485 targetSdkVersion, fromCodePath); 486 } catch (Exception e) { 487 throw InstallerException.from(e); 488 } 489 } 490 getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId, long[] ceDataInodes, String[] codePaths, PackageStats stats)491 public void getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId, 492 long[] ceDataInodes, String[] codePaths, PackageStats stats) 493 throws InstallerException { 494 if (!checkBeforeRemote()) return; 495 if (codePaths != null) { 496 for (String codePath : codePaths) { 497 BlockGuard.getVmPolicy().onPathAccess(codePath); 498 } 499 } 500 try { 501 final long[] res = mInstalld.getAppSize(uuid, packageNames, userId, flags, 502 appId, ceDataInodes, codePaths); 503 stats.codeSize += res[0]; 504 stats.dataSize += res[1]; 505 stats.cacheSize += res[2]; 506 stats.externalCodeSize += res[3]; 507 stats.externalDataSize += res[4]; 508 stats.externalCacheSize += res[5]; 509 } catch (Exception e) { 510 throw InstallerException.from(e); 511 } 512 } 513 getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats)514 public void getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats) 515 throws InstallerException { 516 if (!checkBeforeRemote()) return; 517 try { 518 final long[] res = mInstalld.getUserSize(uuid, userId, flags, appIds); 519 stats.codeSize += res[0]; 520 stats.dataSize += res[1]; 521 stats.cacheSize += res[2]; 522 stats.externalCodeSize += res[3]; 523 stats.externalDataSize += res[4]; 524 stats.externalCacheSize += res[5]; 525 } catch (Exception e) { 526 throw InstallerException.from(e); 527 } 528 } 529 getExternalSize(String uuid, int userId, int flags, int[] appIds)530 public long[] getExternalSize(String uuid, int userId, int flags, int[] appIds) 531 throws InstallerException { 532 if (!checkBeforeRemote()) return new long[6]; 533 try { 534 return mInstalld.getExternalSize(uuid, userId, flags, appIds); 535 } catch (Exception e) { 536 throw InstallerException.from(e); 537 } 538 } 539 540 /** 541 * To get all of the CrateMetadata of the crates for the specified user app by the installd. 542 * 543 * @param uuid the UUID 544 * @param packageNames the application package names 545 * @param userId the user id 546 * @return the array of CrateMetadata 547 */ 548 @Nullable getAppCrates(@onNull String uuid, @NonNull String[] packageNames, @UserIdInt int userId)549 public CrateMetadata[] getAppCrates(@NonNull String uuid, @NonNull String[] packageNames, 550 @UserIdInt int userId) throws InstallerException { 551 if (!checkBeforeRemote()) return null; 552 try { 553 return mInstalld.getAppCrates(uuid, packageNames, userId); 554 } catch (Exception e) { 555 throw InstallerException.from(e); 556 } 557 } 558 559 /** 560 * To retrieve all of the CrateMetadata of the crate for the specified user app by the installd. 561 * 562 * @param uuid the UUID 563 * @param userId the user id 564 * @return the array of CrateMetadata 565 */ 566 @Nullable getUserCrates(String uuid, @UserIdInt int userId)567 public CrateMetadata[] getUserCrates(String uuid, @UserIdInt int userId) 568 throws InstallerException { 569 if (!checkBeforeRemote()) return null; 570 try { 571 return mInstalld.getUserCrates(uuid, userId); 572 } catch (Exception e) { 573 throw InstallerException.from(e); 574 } 575 } 576 setAppQuota(String uuid, int userId, int appId, long cacheQuota)577 public void setAppQuota(String uuid, int userId, int appId, long cacheQuota) 578 throws InstallerException { 579 if (!checkBeforeRemote()) return; 580 try { 581 mInstalld.setAppQuota(uuid, userId, appId, cacheQuota); 582 } catch (Exception e) { 583 throw InstallerException.from(e); 584 } 585 } 586 587 /** 588 * Runs dex optimization. 589 * 590 * @param apkPath Path of target APK 591 * @param uid UID of the package 592 * @param pkgName Name of the package 593 * @param instructionSet Target instruction set to run dex optimization. 594 * @param dexoptNeeded Necessary dex optimization for this request. Check 595 * {@link dalvik.system.DexFile#NO_DEXOPT_NEEDED}, 596 * {@link dalvik.system.DexFile#DEX2OAT_FROM_SCRATCH}, 597 * {@link dalvik.system.DexFile#DEX2OAT_FOR_BOOT_IMAGE}, and 598 * {@link dalvik.system.DexFile#DEX2OAT_FOR_FILTER}. 599 * @param outputPath Output path of generated dex optimization. 600 * @param dexFlags Check {@code DEXOPT_*} for allowed flags. 601 * @param compilerFilter Compiler filter like "verify", "speed-profile". Check 602 * {@code art/libartbase/base/compiler_filter.cc} for full list. 603 * @param volumeUuid UUID of the volume where the package data is stored. {@code null} 604 * represents internal storage. 605 * @param classLoaderContext This encodes the class loader chain (class loader type + class 606 * path) in a format compatible to dex2oat. Check 607 * {@code DexoptUtils.processContextForDexLoad} for further details. 608 * @param seInfo Selinux context to set for generated outputs. 609 * @param downgrade If set, allows downgrading {@code compilerFilter}. If downgrading is not 610 * allowed and requested {@code compilerFilter} is considered as downgrade, 611 * the request will be ignored. 612 * @param targetSdkVersion Target SDK version of the package. 613 * @param profileName Name of reference profile file. 614 * @param dexMetadataPath Specifies the location of dex metadata file. 615 * @param compilationReason Specifies the reason for the compilation like "install". 616 * @return {@code true} if {@code dexopt} is completed. {@code false} if it was cancelled. 617 * 618 * @throws InstallerException if {@code dexopt} fails. 619 */ dexopt(String apkPath, int uid, String pkgName, String instructionSet, int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter, @Nullable String volumeUuid, @Nullable String classLoaderContext, @Nullable String seInfo, boolean downgrade, int targetSdkVersion, @Nullable String profileName, @Nullable String dexMetadataPath, @Nullable String compilationReason)620 public boolean dexopt(String apkPath, int uid, String pkgName, String instructionSet, 621 int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter, 622 @Nullable String volumeUuid, @Nullable String classLoaderContext, 623 @Nullable String seInfo, boolean downgrade, int targetSdkVersion, 624 @Nullable String profileName, @Nullable String dexMetadataPath, 625 @Nullable String compilationReason) 626 throws InstallerException, LegacyDexoptDisabledException { 627 checkLegacyDexoptDisabled(); 628 assertValidInstructionSet(instructionSet); 629 BlockGuard.getVmPolicy().onPathAccess(apkPath); 630 BlockGuard.getVmPolicy().onPathAccess(outputPath); 631 BlockGuard.getVmPolicy().onPathAccess(dexMetadataPath); 632 if (!checkBeforeRemote()) return false; 633 try { 634 return mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath, 635 dexFlags, compilerFilter, volumeUuid, classLoaderContext, seInfo, downgrade, 636 targetSdkVersion, profileName, dexMetadataPath, compilationReason); 637 } catch (Exception e) { 638 throw InstallerException.from(e); 639 } 640 } 641 642 /** 643 * Enables or disables dex optimization blocking. 644 * 645 * <p> Enabling blocking will also involve cancelling pending dexopt call and killing child 646 * processes forked from installd to run dexopt. The pending dexopt call will return false 647 * when it is cancelled. 648 * 649 * @param block set to true to enable blocking / false to disable blocking. 650 */ controlDexOptBlocking(boolean block)651 public void controlDexOptBlocking(boolean block) throws LegacyDexoptDisabledException { 652 checkLegacyDexoptDisabled(); 653 try { 654 mInstalld.controlDexOptBlocking(block); 655 } catch (Exception e) { 656 Slog.w(TAG, "blockDexOpt failed", e); 657 } 658 } 659 660 /** 661 * Analyzes the ART profiles of the given package, possibly merging the information 662 * into the reference profile. Returns whether or not we should optimize the package 663 * based on how much information is in the profile. 664 * 665 * @return one of {@link #PROFILE_ANALYSIS_OPTIMIZE}, 666 * {@link #PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA}, 667 * {@link #PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES} 668 */ mergeProfiles(int uid, String packageName, String profileName)669 public int mergeProfiles(int uid, String packageName, String profileName) 670 throws InstallerException, LegacyDexoptDisabledException { 671 checkLegacyDexoptDisabled(); 672 if (!checkBeforeRemote()) return PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; 673 try { 674 return mInstalld.mergeProfiles(uid, packageName, profileName); 675 } catch (Exception e) { 676 throw InstallerException.from(e); 677 } 678 } 679 680 /** 681 * Dumps profiles associated with a package in a human readable format. 682 */ dumpProfiles(int uid, String packageName, String profileName, String codePath, boolean dumpClassesAndMethods)683 public boolean dumpProfiles(int uid, String packageName, String profileName, String codePath, 684 boolean dumpClassesAndMethods) 685 throws InstallerException, LegacyDexoptDisabledException { 686 checkLegacyDexoptDisabled(); 687 if (!checkBeforeRemote()) return false; 688 BlockGuard.getVmPolicy().onPathAccess(codePath); 689 try { 690 return mInstalld.dumpProfiles(uid, packageName, profileName, codePath, 691 dumpClassesAndMethods); 692 } catch (Exception e) { 693 throw InstallerException.from(e); 694 } 695 } 696 copySystemProfile(String systemProfile, int uid, String packageName, String profileName)697 public boolean copySystemProfile(String systemProfile, int uid, String packageName, 698 String profileName) throws InstallerException, LegacyDexoptDisabledException { 699 checkLegacyDexoptDisabled(); 700 if (!checkBeforeRemote()) return false; 701 try { 702 return mInstalld.copySystemProfile(systemProfile, uid, packageName, profileName); 703 } catch (Exception e) { 704 throw InstallerException.from(e); 705 } 706 } 707 rmdex(String codePath, String instructionSet)708 public void rmdex(String codePath, String instructionSet) 709 throws InstallerException, LegacyDexoptDisabledException { 710 checkLegacyDexoptDisabled(); 711 assertValidInstructionSet(instructionSet); 712 if (!checkBeforeRemote()) return; 713 BlockGuard.getVmPolicy().onPathAccess(codePath); 714 try { 715 mInstalld.rmdex(codePath, instructionSet); 716 } catch (Exception e) { 717 throw InstallerException.from(e); 718 } 719 } 720 721 /** 722 * Remove a directory belonging to a package. 723 */ rmPackageDir(String packageName, String packageDir)724 public void rmPackageDir(String packageName, String packageDir) throws InstallerException { 725 if (!checkBeforeRemote()) return; 726 BlockGuard.getVmPolicy().onPathAccess(packageDir); 727 try { 728 mInstalld.rmPackageDir(packageName, packageDir); 729 } catch (Exception e) { 730 throw InstallerException.from(e); 731 } 732 } 733 clearAppProfiles(String packageName, String profileName)734 public void clearAppProfiles(String packageName, String profileName) 735 throws InstallerException, LegacyDexoptDisabledException { 736 checkLegacyDexoptDisabled(); 737 if (!checkBeforeRemote()) return; 738 try { 739 mInstalld.clearAppProfiles(packageName, profileName); 740 } catch (Exception e) { 741 throw InstallerException.from(e); 742 } 743 } 744 destroyAppProfiles(String packageName)745 public void destroyAppProfiles(String packageName) 746 throws InstallerException, LegacyDexoptDisabledException { 747 checkLegacyDexoptDisabled(); 748 if (!checkBeforeRemote()) return; 749 try { 750 mInstalld.destroyAppProfiles(packageName); 751 } catch (Exception e) { 752 throw InstallerException.from(e); 753 } 754 } 755 756 /** 757 * Deletes the reference profile with the given name of the given package. 758 * @throws InstallerException if the deletion fails. 759 */ deleteReferenceProfile(String packageName, String profileName)760 public void deleteReferenceProfile(String packageName, String profileName) 761 throws InstallerException, LegacyDexoptDisabledException { 762 checkLegacyDexoptDisabled(); 763 if (!checkBeforeRemote()) return; 764 try { 765 mInstalld.deleteReferenceProfile(packageName, profileName); 766 } catch (Exception e) { 767 throw InstallerException.from(e); 768 } 769 } 770 createUserData(String uuid, int userId, int userSerial, int flags)771 public void createUserData(String uuid, int userId, int userSerial, int flags) 772 throws InstallerException { 773 if (!checkBeforeRemote()) return; 774 try { 775 mInstalld.createUserData(uuid, userId, userSerial, flags); 776 } catch (Exception e) { 777 throw InstallerException.from(e); 778 } 779 } 780 destroyUserData(String uuid, int userId, int flags)781 public void destroyUserData(String uuid, int userId, int flags) throws InstallerException { 782 if (!checkBeforeRemote()) return; 783 try { 784 mInstalld.destroyUserData(uuid, userId, flags); 785 } catch (Exception e) { 786 throw InstallerException.from(e); 787 } 788 } 789 790 /** 791 * Deletes cache from specified uuid until targetFreeBytes amount of space is free. 792 * flag denotes aggressive or non-aggresive mode where cache under quota is eligible or not 793 * respectively for clearing. 794 */ freeCache(String uuid, long targetFreeBytes, int flags)795 public void freeCache(String uuid, long targetFreeBytes, int flags) throws InstallerException { 796 if (!checkBeforeRemote()) return; 797 try { 798 mInstalld.freeCache(uuid, targetFreeBytes, flags); 799 } catch (Exception e) { 800 throw InstallerException.from(e); 801 } 802 } 803 804 /** 805 * Links the 32 bit native library directory in an application's data 806 * directory to the real location for backward compatibility. Note that no 807 * such symlink is created for 64 bit shared libraries. 808 */ linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32, int userId)809 public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32, 810 int userId) throws InstallerException { 811 if (!checkBeforeRemote()) return; 812 BlockGuard.getVmPolicy().onPathAccess(nativeLibPath32); 813 try { 814 mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId); 815 } catch (Exception e) { 816 throw InstallerException.from(e); 817 } 818 } 819 820 /** 821 * Creates an oat dir for given package and instruction set. 822 */ createOatDir(String packageName, String oatDir, String dexInstructionSet)823 public void createOatDir(String packageName, String oatDir, String dexInstructionSet) 824 throws InstallerException { 825 // This method should be allowed even if ART Service is enabled, because it's used for 826 // creating oat dirs before creating hard links for partial installation. 827 // TODO(b/274658735): Add an ART Service API to support hard linking. 828 if (!checkBeforeRemote()) return; 829 try { 830 mInstalld.createOatDir(packageName, oatDir, dexInstructionSet); 831 } catch (Exception e) { 832 throw InstallerException.from(e); 833 } 834 } 835 836 /** 837 * Creates a hardlink for a path. 838 */ linkFile(String packageName, String relativePath, String fromBase, String toBase)839 public void linkFile(String packageName, String relativePath, String fromBase, String toBase) 840 throws InstallerException { 841 if (!checkBeforeRemote()) return; 842 BlockGuard.getVmPolicy().onPathAccess(fromBase); 843 BlockGuard.getVmPolicy().onPathAccess(toBase); 844 try { 845 mInstalld.linkFile(packageName, relativePath, fromBase, toBase); 846 } catch (Exception e) { 847 throw InstallerException.from(e); 848 } 849 } 850 851 /** 852 * Moves oat/vdex/art from "B" set defined by ro.boot.slot_suffix to the default set. 853 */ moveAb(String packageName, String apkPath, String instructionSet, String outputPath)854 public void moveAb(String packageName, String apkPath, String instructionSet, String outputPath) 855 throws InstallerException { 856 if (!checkBeforeRemote()) return; 857 BlockGuard.getVmPolicy().onPathAccess(apkPath); 858 BlockGuard.getVmPolicy().onPathAccess(outputPath); 859 try { 860 mInstalld.moveAb(packageName, apkPath, instructionSet, outputPath); 861 } catch (Exception e) { 862 throw InstallerException.from(e); 863 } 864 } 865 866 /** 867 * Deletes the optimized artifacts generated by ART and returns the number 868 * of freed bytes. 869 */ deleteOdex(String packageName, String apkPath, String instructionSet, String outputPath)870 public long deleteOdex(String packageName, String apkPath, String instructionSet, 871 String outputPath) throws InstallerException, LegacyDexoptDisabledException { 872 checkLegacyDexoptDisabled(); 873 if (!checkBeforeRemote()) return -1; 874 BlockGuard.getVmPolicy().onPathAccess(apkPath); 875 BlockGuard.getVmPolicy().onPathAccess(outputPath); 876 try { 877 return mInstalld.deleteOdex(packageName, apkPath, instructionSet, outputPath); 878 } catch (Exception e) { 879 throw InstallerException.from(e); 880 } 881 } 882 reconcileSecondaryDexFile(String apkPath, String packageName, int uid, String[] isas, @Nullable String volumeUuid, int flags)883 public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid, 884 String[] isas, @Nullable String volumeUuid, int flags) 885 throws InstallerException, LegacyDexoptDisabledException { 886 checkLegacyDexoptDisabled(); 887 for (int i = 0; i < isas.length; i++) { 888 assertValidInstructionSet(isas[i]); 889 } 890 if (!checkBeforeRemote()) return false; 891 BlockGuard.getVmPolicy().onPathAccess(apkPath); 892 try { 893 return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas, 894 volumeUuid, flags); 895 } catch (Exception e) { 896 throw InstallerException.from(e); 897 } 898 } 899 hashSecondaryDexFile(String dexPath, String packageName, int uid, @Nullable String volumeUuid, int flags)900 public byte[] hashSecondaryDexFile(String dexPath, String packageName, int uid, 901 @Nullable String volumeUuid, int flags) throws InstallerException { 902 if (!checkBeforeRemote()) return new byte[0]; 903 BlockGuard.getVmPolicy().onPathAccess(dexPath); 904 try { 905 return mInstalld.hashSecondaryDexFile(dexPath, packageName, uid, volumeUuid, flags); 906 } catch (Exception e) { 907 throw InstallerException.from(e); 908 } 909 } 910 createProfileSnapshot(int appId, String packageName, String profileName, String classpath)911 public boolean createProfileSnapshot(int appId, String packageName, String profileName, 912 String classpath) throws InstallerException, LegacyDexoptDisabledException { 913 checkLegacyDexoptDisabled(); 914 if (!checkBeforeRemote()) return false; 915 try { 916 return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath); 917 } catch (Exception e) { 918 throw InstallerException.from(e); 919 } 920 } 921 destroyProfileSnapshot(String packageName, String profileName)922 public void destroyProfileSnapshot(String packageName, String profileName) 923 throws InstallerException, LegacyDexoptDisabledException { 924 checkLegacyDexoptDisabled(); 925 if (!checkBeforeRemote()) return; 926 try { 927 mInstalld.destroyProfileSnapshot(packageName, profileName); 928 } catch (Exception e) { 929 throw InstallerException.from(e); 930 } 931 } 932 invalidateMounts()933 public void invalidateMounts() throws InstallerException { 934 if (!checkBeforeRemote()) return; 935 try { 936 mInstalld.invalidateMounts(); 937 } catch (Exception e) { 938 throw InstallerException.from(e); 939 } 940 } 941 isQuotaSupported(String volumeUuid)942 public boolean isQuotaSupported(String volumeUuid) throws InstallerException { 943 if (!checkBeforeRemote()) return false; 944 try { 945 return mInstalld.isQuotaSupported(volumeUuid); 946 } catch (Exception e) { 947 throw InstallerException.from(e); 948 } 949 } 950 951 /** 952 * Bind mount private volume CE and DE mirror storage. 953 */ tryMountDataMirror(String volumeUuid)954 public void tryMountDataMirror(String volumeUuid) throws InstallerException { 955 if (!checkBeforeRemote()) return; 956 try { 957 mInstalld.tryMountDataMirror(volumeUuid); 958 } catch (Exception e) { 959 throw InstallerException.from(e); 960 } 961 } 962 963 /** 964 * Unmount private volume CE and DE mirror storage. 965 */ onPrivateVolumeRemoved(String volumeUuid)966 public void onPrivateVolumeRemoved(String volumeUuid) throws InstallerException { 967 if (!checkBeforeRemote()) return; 968 try { 969 mInstalld.onPrivateVolumeRemoved(volumeUuid); 970 } catch (Exception e) { 971 throw InstallerException.from(e); 972 } 973 } 974 975 /** 976 * Prepares the app profile for the package at the given path: 977 * <ul> 978 * <li>Creates the current profile for the given user ID, unless the user ID is 979 * {@code UserHandle.USER_NULL}.</li> 980 * <li>Merges the profile from the dex metadata file (if present) into the reference 981 * profile.</li> 982 * </ul> 983 */ prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId, String profileName, String codePath, String dexMetadataPath)984 public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId, 985 String profileName, String codePath, String dexMetadataPath) 986 throws InstallerException, LegacyDexoptDisabledException { 987 checkLegacyDexoptDisabled(); 988 if (!checkBeforeRemote()) return false; 989 BlockGuard.getVmPolicy().onPathAccess(codePath); 990 BlockGuard.getVmPolicy().onPathAccess(dexMetadataPath); 991 try { 992 return mInstalld.prepareAppProfile(pkg, userId, appId, profileName, codePath, 993 dexMetadataPath); 994 } catch (Exception e) { 995 throw InstallerException.from(e); 996 } 997 } 998 999 /** 1000 * Snapshots user data of the given package. 1001 * 1002 * @param pkg name of the package to snapshot user data for. 1003 * @param userId id of the user whose data to snapshot. 1004 * @param snapshotId id of this snapshot. 1005 * @param storageFlags flags controlling which data (CE or DE) to snapshot. 1006 * 1007 * @return {@code true} if the snapshot was taken successfully, or {@code false} if a remote 1008 * call shouldn't be continued. See {@link #checkBeforeRemote}. 1009 * 1010 * @throws InstallerException if failed to snapshot user data. 1011 */ snapshotAppData(String pkg, @UserIdInt int userId, int snapshotId, int storageFlags)1012 public boolean snapshotAppData(String pkg, @UserIdInt int userId, int snapshotId, 1013 int storageFlags) throws InstallerException { 1014 if (!checkBeforeRemote()) return false; 1015 1016 try { 1017 mInstalld.snapshotAppData(null, pkg, userId, snapshotId, storageFlags); 1018 return true; 1019 } catch (Exception e) { 1020 throw InstallerException.from(e); 1021 } 1022 } 1023 1024 /** 1025 * Restores user data snapshot of the given package. 1026 * 1027 * @param pkg name of the package to restore user data for. 1028 * @param appId id of the package to restore user data for. 1029 * @param userId id of the user whose data to restore. 1030 * @param snapshotId id of the snapshot to restore. 1031 * @param storageFlags flags controlling which data (CE or DE) to restore. 1032 * 1033 * @return {@code true} if user data restore was successful, or {@code false} if a remote call 1034 * shouldn't be continued. See {@link #checkBeforeRemote}. 1035 * 1036 * @throws InstallerException if failed to restore user data. 1037 */ restoreAppDataSnapshot(String pkg, @AppIdInt int appId, String seInfo, @UserIdInt int userId, int snapshotId, int storageFlags)1038 public boolean restoreAppDataSnapshot(String pkg, @AppIdInt int appId, String seInfo, 1039 @UserIdInt int userId, int snapshotId, int storageFlags) throws InstallerException { 1040 if (!checkBeforeRemote()) return false; 1041 1042 try { 1043 mInstalld.restoreAppDataSnapshot(null, pkg, appId, seInfo, userId, snapshotId, 1044 storageFlags); 1045 return true; 1046 } catch (Exception e) { 1047 throw InstallerException.from(e); 1048 } 1049 } 1050 1051 /** 1052 * Deletes user data snapshot of the given package. 1053 * 1054 * @param pkg name of the package to delete user data snapshot for. 1055 * @param userId id of the user whose user data snapshot to delete. 1056 * @param snapshotId id of the snapshot to delete. 1057 * @param storageFlags flags controlling which user data snapshot (CE or DE) to delete. 1058 * 1059 * @return {@code true} if user data snapshot was successfully deleted, or {@code false} if a 1060 * remote call shouldn't be continued. See {@link #checkBeforeRemote}. 1061 * 1062 * @throws InstallerException if failed to delete user data snapshot. 1063 */ destroyAppDataSnapshot(String pkg, @UserIdInt int userId, int snapshotId, int storageFlags)1064 public boolean destroyAppDataSnapshot(String pkg, @UserIdInt int userId, 1065 int snapshotId, int storageFlags) throws InstallerException { 1066 if (!checkBeforeRemote()) return false; 1067 1068 try { 1069 mInstalld.destroyAppDataSnapshot(null, pkg, userId, 0, snapshotId, storageFlags); 1070 return true; 1071 } catch (Exception e) { 1072 throw InstallerException.from(e); 1073 } 1074 } 1075 1076 /** 1077 * Deletes all snapshots of credential encrypted user data, where the snapshot id is not 1078 * included in {@code retainSnapshotIds}. 1079 * 1080 * @param userId id of the user whose user data snapshots to delete. 1081 * @param retainSnapshotIds ids of the snapshots that should not be deleted. 1082 * 1083 * @return {@code true} if the operation was successful, or {@code false} if a remote call 1084 * shouldn't be continued. See {@link #checkBeforeRemote}. 1085 * 1086 * @throws InstallerException if failed to delete user data snapshot. 1087 */ destroyCeSnapshotsNotSpecified(@serIdInt int userId, int[] retainSnapshotIds)1088 public boolean destroyCeSnapshotsNotSpecified(@UserIdInt int userId, 1089 int[] retainSnapshotIds) throws InstallerException { 1090 if (!checkBeforeRemote()) return false; 1091 1092 try { 1093 mInstalld.destroyCeSnapshotsNotSpecified(null, userId, retainSnapshotIds); 1094 return true; 1095 } catch (Exception e) { 1096 throw InstallerException.from(e); 1097 } 1098 } 1099 1100 /** 1101 * Migrates obb data from its legacy location {@code /data/media/obb} to 1102 * {@code /data/media/0/Android/obb}. This call is idempotent and a fast no-op if data has 1103 * already been migrated. 1104 * 1105 * @throws InstallerException if an error occurs. 1106 */ migrateLegacyObbData()1107 public boolean migrateLegacyObbData() throws InstallerException { 1108 if (!checkBeforeRemote()) return false; 1109 1110 try { 1111 mInstalld.migrateLegacyObbData(); 1112 return true; 1113 } catch (Exception e) { 1114 throw InstallerException.from(e); 1115 } 1116 } 1117 assertValidInstructionSet(String instructionSet)1118 private static void assertValidInstructionSet(String instructionSet) 1119 throws InstallerException { 1120 for (String abi : Build.SUPPORTED_ABIS) { 1121 if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) { 1122 return; 1123 } 1124 } 1125 throw new InstallerException("Invalid instruction set: " + instructionSet); 1126 } 1127 compileLayouts(String apkPath, String packageName, String outDexFile, int uid)1128 public boolean compileLayouts(String apkPath, String packageName, String outDexFile, int uid) { 1129 try { 1130 return mInstalld.compileLayouts(apkPath, packageName, outDexFile, uid); 1131 } catch (RemoteException e) { 1132 return false; 1133 } 1134 } 1135 1136 /** 1137 * Returns the visibility of the optimized artifacts. 1138 * 1139 * @param packageName name of the package. 1140 * @param apkPath path to the APK. 1141 * @param instructionSet instruction set of the optimized artifacts. 1142 * @param outputPath path to the directory that contains the optimized artifacts (i.e., the 1143 * directory that {@link #dexopt} outputs to). 1144 * 1145 * @return {@link #ODEX_NOT_FOUND} if the optimized artifacts are not found, or 1146 * {@link #ODEX_IS_PUBLIC} if the optimized artifacts are accessible by all apps, or 1147 * {@link #ODEX_IS_PRIVATE} if the optimized artifacts are only accessible by this app. 1148 * 1149 * @throws InstallerException if failed to get the visibility of the optimized artifacts. 1150 */ getOdexVisibility(String packageName, String apkPath, String instructionSet, String outputPath)1151 public int getOdexVisibility(String packageName, String apkPath, String instructionSet, 1152 String outputPath) throws InstallerException, LegacyDexoptDisabledException { 1153 checkLegacyDexoptDisabled(); 1154 if (!checkBeforeRemote()) return -1; 1155 BlockGuard.getVmPolicy().onPathAccess(apkPath); 1156 BlockGuard.getVmPolicy().onPathAccess(outputPath); 1157 try { 1158 return mInstalld.getOdexVisibility(packageName, apkPath, instructionSet, outputPath); 1159 } catch (Exception e) { 1160 throw InstallerException.from(e); 1161 } 1162 } 1163 1164 public static class InstallerException extends Exception { InstallerException(String detailMessage)1165 public InstallerException(String detailMessage) { 1166 super(detailMessage); 1167 } 1168 from(Exception e)1169 public static InstallerException from(Exception e) throws InstallerException { 1170 throw new InstallerException(e.toString()); 1171 } 1172 } 1173 1174 /** 1175 * A checked exception that is thrown in legacy dexopt code paths when ART Service should be 1176 * used instead. 1177 */ 1178 public static class LegacyDexoptDisabledException extends Exception { 1179 // TODO(b/260124949): Remove the legacy dexopt code paths, i.e. this exception and all code 1180 // that may throw it. LegacyDexoptDisabledException()1181 public LegacyDexoptDisabledException() { 1182 super("Invalid call to legacy dexopt method while ART Service is in use."); 1183 } 1184 } 1185 1186 /** 1187 * Throws LegacyDexoptDisabledException if ART Service should be used instead of the 1188 * {@link android.os.IInstalld} method that follows this method call. 1189 */ checkLegacyDexoptDisabled()1190 public static void checkLegacyDexoptDisabled() throws LegacyDexoptDisabledException { 1191 if (useArtService()) { 1192 throw new LegacyDexoptDisabledException(); 1193 } 1194 } 1195 } 1196