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