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.IBinder.DeathRecipient; 30 import android.os.IInstalld; 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.io.FileDescriptor; 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.List; 47 import java.util.concurrent.CompletableFuture; 48 49 public class Installer extends SystemService { 50 private static final String TAG = "Installer"; 51 52 /* *************************************************************************** 53 * IMPORTANT: These values are passed to native code. Keep them in sync with 54 * frameworks/native/cmds/installd/installd_constants.h 55 * **************************************************************************/ 56 /** Application should be visible to everyone */ 57 public static final int DEXOPT_PUBLIC = 1 << 1; 58 /** Application wants to allow debugging of its code */ 59 public static final int DEXOPT_DEBUGGABLE = 1 << 2; 60 /** The system boot has finished */ 61 public static final int DEXOPT_BOOTCOMPLETE = 1 << 3; 62 /** Hint that the dexopt type is profile-guided. */ 63 public static final int DEXOPT_PROFILE_GUIDED = 1 << 4; 64 /** The compilation is for a secondary dex file. */ 65 public static final int DEXOPT_SECONDARY_DEX = 1 << 5; 66 /** Ignore the result of dexoptNeeded and force compilation. */ 67 public static final int DEXOPT_FORCE = 1 << 6; 68 /** Indicates that the dex file passed to dexopt in on CE storage. */ 69 public static final int DEXOPT_STORAGE_CE = 1 << 7; 70 /** Indicates that the dex file passed to dexopt in on DE storage. */ 71 public static final int DEXOPT_STORAGE_DE = 1 << 8; 72 /** Indicates that dexopt is invoked from the background service. */ 73 public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9; 74 /** Indicates that dexopt should restrict access to private APIs. */ 75 public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10; 76 /** Indicates that dexopt should convert to CompactDex. */ 77 public static final int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11; 78 /** Indicates that dexopt should generate an app image */ 79 public static final int DEXOPT_GENERATE_APP_IMAGE = 1 << 12; 80 /** Indicates that dexopt may be run with different performance / priority tuned for restore */ 81 public static final int DEXOPT_FOR_RESTORE = 1 << 13; // TODO(b/135202722): remove 82 83 /** The result of the profile analysis indicating that the app should be optimized. */ 84 public static final int PROFILE_ANALYSIS_OPTIMIZE = 1; 85 /** The result of the profile analysis indicating that the app should not be optimized. */ 86 public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA = 2; 87 /** 88 * The result of the profile analysis indicating that the app should not be optimized because 89 * the profiles are empty. 90 */ 91 public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3; 92 93 94 public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE; 95 public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE; 96 public static final int FLAG_STORAGE_EXTERNAL = IInstalld.FLAG_STORAGE_EXTERNAL; 97 98 public static final int FLAG_CLEAR_CACHE_ONLY = IInstalld.FLAG_CLEAR_CACHE_ONLY; 99 public static final int FLAG_CLEAR_CODE_CACHE_ONLY = IInstalld.FLAG_CLEAR_CODE_CACHE_ONLY; 100 101 public static final int FLAG_FREE_CACHE_V2 = IInstalld.FLAG_FREE_CACHE_V2; 102 public static final int FLAG_FREE_CACHE_V2_DEFY_QUOTA = IInstalld.FLAG_FREE_CACHE_V2_DEFY_QUOTA; 103 public static final int FLAG_FREE_CACHE_NOOP = IInstalld.FLAG_FREE_CACHE_NOOP; 104 105 public static final int FLAG_USE_QUOTA = IInstalld.FLAG_USE_QUOTA; 106 public static final int FLAG_FORCE = IInstalld.FLAG_FORCE; 107 108 public static final int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES = 109 IInstalld.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES; 110 111 private final boolean mIsolated; 112 113 private volatile IInstalld mInstalld; 114 private volatile Object mWarnIfHeld; 115 Installer(Context context)116 public Installer(Context context) { 117 this(context, false); 118 } 119 120 /** 121 * @param isolated indicates if this object should <em>not</em> connect to 122 * the real {@code installd}. All remote calls will be ignored 123 * unless you extend this class and intercept them. 124 */ Installer(Context context, boolean isolated)125 public Installer(Context context, boolean isolated) { 126 super(context); 127 mIsolated = isolated; 128 } 129 130 /** 131 * Yell loudly if someone tries making future calls while holding a lock on 132 * the given object. 133 */ setWarnIfHeld(Object warnIfHeld)134 public void setWarnIfHeld(Object warnIfHeld) { 135 mWarnIfHeld = warnIfHeld; 136 } 137 138 @Override onStart()139 public void onStart() { 140 if (mIsolated) { 141 mInstalld = null; 142 } else { 143 connect(); 144 } 145 } 146 connect()147 private void connect() { 148 IBinder binder = ServiceManager.getService("installd"); 149 if (binder != null) { 150 try { 151 binder.linkToDeath(new DeathRecipient() { 152 @Override 153 public void binderDied() { 154 Slog.w(TAG, "installd died; reconnecting"); 155 connect(); 156 } 157 }, 0); 158 } catch (RemoteException e) { 159 binder = null; 160 } 161 } 162 163 if (binder != null) { 164 mInstalld = IInstalld.Stub.asInterface(binder); 165 try { 166 invalidateMounts(); 167 } catch (InstallerException ignored) { 168 } 169 } else { 170 Slog.w(TAG, "installd not found; trying again"); 171 BackgroundThread.getHandler().postDelayed(() -> { 172 connect(); 173 }, DateUtils.SECOND_IN_MILLIS); 174 } 175 } 176 177 /** 178 * Do several pre-flight checks before making a remote call. 179 * 180 * @return if the remote call should continue. 181 */ checkBeforeRemote()182 private boolean checkBeforeRemote() { 183 if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) { 184 Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" 185 + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable()); 186 } 187 if (mIsolated) { 188 Slog.i(TAG, "Ignoring request because this installer is isolated"); 189 return false; 190 } else { 191 return true; 192 } 193 } 194 buildCreateAppDataArgs(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion)195 private static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName, 196 int userId, int flags, int appId, String seInfo, int targetSdkVersion) { 197 final CreateAppDataArgs args = new CreateAppDataArgs(); 198 args.uuid = uuid; 199 args.packageName = packageName; 200 args.userId = userId; 201 args.flags = flags; 202 args.appId = appId; 203 args.seInfo = seInfo; 204 args.targetSdkVersion = targetSdkVersion; 205 return args; 206 } 207 buildPlaceholderCreateAppDataResult()208 private static CreateAppDataResult buildPlaceholderCreateAppDataResult() { 209 final CreateAppDataResult result = new CreateAppDataResult(); 210 result.ceDataInode = -1; 211 result.exceptionCode = 0; 212 result.exceptionMessage = null; 213 return result; 214 } 215 216 /** 217 * @deprecated callers are encouraged to migrate to using {@link Batch} to 218 * more efficiently handle operations in bulk. 219 */ 220 @Deprecated createAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion)221 public long createAppData(String uuid, String packageName, int userId, int flags, int appId, 222 String seInfo, int targetSdkVersion) throws InstallerException { 223 final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags, 224 appId, seInfo, targetSdkVersion); 225 final CreateAppDataResult result = createAppData(args); 226 if (result.exceptionCode == 0) { 227 return result.ceDataInode; 228 } else { 229 throw new InstallerException(result.exceptionMessage); 230 } 231 } 232 createAppData(@onNull CreateAppDataArgs args)233 public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args) 234 throws InstallerException { 235 if (!checkBeforeRemote()) { 236 return buildPlaceholderCreateAppDataResult(); 237 } 238 try { 239 return mInstalld.createAppData(args); 240 } catch (Exception e) { 241 throw InstallerException.from(e); 242 } 243 } 244 createAppDataBatched(@onNull CreateAppDataArgs[] args)245 public @NonNull CreateAppDataResult[] createAppDataBatched(@NonNull CreateAppDataArgs[] args) 246 throws InstallerException { 247 if (!checkBeforeRemote()) { 248 final CreateAppDataResult[] results = new CreateAppDataResult[args.length]; 249 Arrays.fill(results, buildPlaceholderCreateAppDataResult()); 250 return results; 251 } 252 try { 253 return mInstalld.createAppDataBatched(args); 254 } catch (Exception e) { 255 throw InstallerException.from(e); 256 } 257 } 258 259 /** 260 * Class that collects multiple {@code installd} operations together in an 261 * attempt to more efficiently execute them in bulk. 262 * <p> 263 * Instead of returning results immediately, {@link CompletableFuture} 264 * instances are returned which can be used to chain follow-up work for each 265 * request. 266 * <p> 267 * The creator of this object <em>must</em> invoke {@link #execute()} 268 * exactly once to begin execution of all pending operations. Once execution 269 * has been kicked off, no additional events can be enqueued into this 270 * instance, but multiple instances can safely exist in parallel. 271 */ 272 public static class Batch { 273 private static final int CREATE_APP_DATA_BATCH_SIZE = 256; 274 275 private boolean mExecuted; 276 277 private final List<CreateAppDataArgs> mArgs = new ArrayList<>(); 278 private final List<CompletableFuture<Long>> mFutures = new ArrayList<>(); 279 280 /** 281 * Enqueue the given {@code installd} operation to be executed in the 282 * future when {@link #execute(Installer)} is invoked. 283 * <p> 284 * Callers of this method are not required to hold a monitor lock on an 285 * {@link Installer} object. 286 */ createAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion)287 public synchronized @NonNull CompletableFuture<Long> createAppData(String uuid, 288 String packageName, int userId, int flags, int appId, String seInfo, 289 int targetSdkVersion) { 290 if (mExecuted) throw new IllegalStateException(); 291 292 final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags, 293 appId, seInfo, targetSdkVersion); 294 final CompletableFuture<Long> future = new CompletableFuture<>(); 295 mArgs.add(args); 296 mFutures.add(future); 297 return future; 298 } 299 300 /** 301 * Execute all pending {@code installd} operations that have been 302 * collected by this batch in a blocking fashion. 303 * <p> 304 * Callers of this method <em>must</em> hold a monitor lock on the given 305 * {@link Installer} object. 306 */ execute(@onNull Installer installer)307 public synchronized void execute(@NonNull Installer installer) throws InstallerException { 308 if (mExecuted) throw new IllegalStateException(); 309 mExecuted = true; 310 311 final int size = mArgs.size(); 312 for (int i = 0; i < size; i += CREATE_APP_DATA_BATCH_SIZE) { 313 final CreateAppDataArgs[] args = new CreateAppDataArgs[Math.min(size - i, 314 CREATE_APP_DATA_BATCH_SIZE)]; 315 for (int j = 0; j < args.length; j++) { 316 args[j] = mArgs.get(i + j); 317 } 318 final CreateAppDataResult[] results = installer.createAppDataBatched(args); 319 for (int j = 0; j < args.length; j++) { 320 final CreateAppDataResult result = results[j]; 321 final CompletableFuture<Long> future = mFutures.get(i + j); 322 if (result.exceptionCode == 0) { 323 future.complete(result.ceDataInode); 324 } else { 325 future.completeExceptionally( 326 new InstallerException(result.exceptionMessage)); 327 } 328 } 329 } 330 } 331 } 332 restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo)333 public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, 334 String seInfo) throws InstallerException { 335 if (!checkBeforeRemote()) return; 336 try { 337 mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo); 338 } catch (Exception e) { 339 throw InstallerException.from(e); 340 } 341 } 342 migrateAppData(String uuid, String packageName, int userId, int flags)343 public void migrateAppData(String uuid, String packageName, int userId, int flags) 344 throws InstallerException { 345 if (!checkBeforeRemote()) return; 346 try { 347 mInstalld.migrateAppData(uuid, packageName, userId, flags); 348 } catch (Exception e) { 349 throw InstallerException.from(e); 350 } 351 } 352 clearAppData(String uuid, String packageName, int userId, int flags, long ceDataInode)353 public void clearAppData(String uuid, String packageName, int userId, int flags, 354 long ceDataInode) throws InstallerException { 355 if (!checkBeforeRemote()) return; 356 try { 357 mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode); 358 } catch (Exception e) { 359 throw InstallerException.from(e); 360 } 361 } 362 destroyAppData(String uuid, String packageName, int userId, int flags, long ceDataInode)363 public void destroyAppData(String uuid, String packageName, int userId, int flags, 364 long ceDataInode) throws InstallerException { 365 if (!checkBeforeRemote()) return; 366 try { 367 mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode); 368 } catch (Exception e) { 369 throw InstallerException.from(e); 370 } 371 } 372 fixupAppData(String uuid, int flags)373 public void fixupAppData(String uuid, int flags) throws InstallerException { 374 if (!checkBeforeRemote()) return; 375 try { 376 mInstalld.fixupAppData(uuid, flags); 377 } catch (Exception e) { 378 throw InstallerException.from(e); 379 } 380 } 381 moveCompleteApp(String fromUuid, String toUuid, String packageName, int appId, String seInfo, int targetSdkVersion, String fromCodePath)382 public void moveCompleteApp(String fromUuid, String toUuid, String packageName, 383 int appId, String seInfo, int targetSdkVersion, 384 String fromCodePath) throws InstallerException { 385 if (!checkBeforeRemote()) return; 386 try { 387 mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, appId, seInfo, 388 targetSdkVersion, fromCodePath); 389 } catch (Exception e) { 390 throw InstallerException.from(e); 391 } 392 } 393 getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId, long[] ceDataInodes, String[] codePaths, PackageStats stats)394 public void getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId, 395 long[] ceDataInodes, String[] codePaths, PackageStats stats) 396 throws InstallerException { 397 if (!checkBeforeRemote()) return; 398 if (codePaths != null) { 399 for (String codePath : codePaths) { 400 BlockGuard.getVmPolicy().onPathAccess(codePath); 401 } 402 } 403 try { 404 final long[] res = mInstalld.getAppSize(uuid, packageNames, userId, flags, 405 appId, ceDataInodes, codePaths); 406 stats.codeSize += res[0]; 407 stats.dataSize += res[1]; 408 stats.cacheSize += res[2]; 409 stats.externalCodeSize += res[3]; 410 stats.externalDataSize += res[4]; 411 stats.externalCacheSize += res[5]; 412 } catch (Exception e) { 413 throw InstallerException.from(e); 414 } 415 } 416 getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats)417 public void getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats) 418 throws InstallerException { 419 if (!checkBeforeRemote()) return; 420 try { 421 final long[] res = mInstalld.getUserSize(uuid, userId, flags, appIds); 422 stats.codeSize += res[0]; 423 stats.dataSize += res[1]; 424 stats.cacheSize += res[2]; 425 stats.externalCodeSize += res[3]; 426 stats.externalDataSize += res[4]; 427 stats.externalCacheSize += res[5]; 428 } catch (Exception e) { 429 throw InstallerException.from(e); 430 } 431 } 432 getExternalSize(String uuid, int userId, int flags, int[] appIds)433 public long[] getExternalSize(String uuid, int userId, int flags, int[] appIds) 434 throws InstallerException { 435 if (!checkBeforeRemote()) return new long[6]; 436 try { 437 return mInstalld.getExternalSize(uuid, userId, flags, appIds); 438 } catch (Exception e) { 439 throw InstallerException.from(e); 440 } 441 } 442 443 /** 444 * To get all of the CrateMetadata of the crates for the specified user app by the installd. 445 * 446 * @param uuid the UUID 447 * @param packageNames the application package names 448 * @param userId the user id 449 * @return the array of CrateMetadata 450 */ 451 @Nullable getAppCrates(@onNull String uuid, @NonNull String[] packageNames, @UserIdInt int userId)452 public CrateMetadata[] getAppCrates(@NonNull String uuid, @NonNull String[] packageNames, 453 @UserIdInt int userId) throws InstallerException { 454 if (!checkBeforeRemote()) return null; 455 try { 456 return mInstalld.getAppCrates(uuid, packageNames, userId); 457 } catch (Exception e) { 458 throw InstallerException.from(e); 459 } 460 } 461 462 /** 463 * To retrieve all of the CrateMetadata of the crate for the specified user app by the installd. 464 * 465 * @param uuid the UUID 466 * @param userId the user id 467 * @return the array of CrateMetadata 468 */ 469 @Nullable getUserCrates(String uuid, @UserIdInt int userId)470 public CrateMetadata[] getUserCrates(String uuid, @UserIdInt int userId) 471 throws InstallerException { 472 if (!checkBeforeRemote()) return null; 473 try { 474 return mInstalld.getUserCrates(uuid, userId); 475 } catch (Exception e) { 476 throw InstallerException.from(e); 477 } 478 } 479 setAppQuota(String uuid, int userId, int appId, long cacheQuota)480 public void setAppQuota(String uuid, int userId, int appId, long cacheQuota) 481 throws InstallerException { 482 if (!checkBeforeRemote()) return; 483 try { 484 mInstalld.setAppQuota(uuid, userId, appId, cacheQuota); 485 } catch (Exception e) { 486 throw InstallerException.from(e); 487 } 488 } 489 dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet, int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade, int targetSdkVersion, @Nullable String profileName, @Nullable String dexMetadataPath, @Nullable String compilationReason)490 public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet, 491 int dexoptNeeded, @Nullable String outputPath, int dexFlags, 492 String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries, 493 @Nullable String seInfo, boolean downgrade, int targetSdkVersion, 494 @Nullable String profileName, @Nullable String dexMetadataPath, 495 @Nullable String compilationReason) throws InstallerException { 496 assertValidInstructionSet(instructionSet); 497 BlockGuard.getVmPolicy().onPathAccess(apkPath); 498 BlockGuard.getVmPolicy().onPathAccess(outputPath); 499 BlockGuard.getVmPolicy().onPathAccess(dexMetadataPath); 500 if (!checkBeforeRemote()) return; 501 try { 502 mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath, 503 dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade, 504 targetSdkVersion, profileName, dexMetadataPath, compilationReason); 505 } catch (Exception e) { 506 throw InstallerException.from(e); 507 } 508 } 509 510 /** 511 * Analyzes the ART profiles of the given package, possibly merging the information 512 * into the reference profile. Returns whether or not we should optimize the package 513 * based on how much information is in the profile. 514 * 515 * @return one of {@link #PROFILE_ANALYSIS_OPTIMIZE}, 516 * {@link #PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA}, 517 * {@link #PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES} 518 */ mergeProfiles(int uid, String packageName, String profileName)519 public int mergeProfiles(int uid, String packageName, String profileName) 520 throws InstallerException { 521 if (!checkBeforeRemote()) return PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA; 522 try { 523 return mInstalld.mergeProfiles(uid, packageName, profileName); 524 } catch (Exception e) { 525 throw InstallerException.from(e); 526 } 527 } 528 dumpProfiles(int uid, String packageName, String profileName, String codePath)529 public boolean dumpProfiles(int uid, String packageName, String profileName, String codePath) 530 throws InstallerException { 531 if (!checkBeforeRemote()) return false; 532 BlockGuard.getVmPolicy().onPathAccess(codePath); 533 try { 534 return mInstalld.dumpProfiles(uid, packageName, profileName, codePath); 535 } catch (Exception e) { 536 throw InstallerException.from(e); 537 } 538 } 539 copySystemProfile(String systemProfile, int uid, String packageName, String profileName)540 public boolean copySystemProfile(String systemProfile, int uid, String packageName, 541 String profileName) throws InstallerException { 542 if (!checkBeforeRemote()) return false; 543 try { 544 return mInstalld.copySystemProfile(systemProfile, uid, packageName, profileName); 545 } catch (Exception e) { 546 throw InstallerException.from(e); 547 } 548 } 549 rmdex(String codePath, String instructionSet)550 public void rmdex(String codePath, String instructionSet) throws InstallerException { 551 assertValidInstructionSet(instructionSet); 552 if (!checkBeforeRemote()) return; 553 BlockGuard.getVmPolicy().onPathAccess(codePath); 554 try { 555 mInstalld.rmdex(codePath, instructionSet); 556 } catch (Exception e) { 557 throw InstallerException.from(e); 558 } 559 } 560 rmPackageDir(String packageDir)561 public void rmPackageDir(String packageDir) throws InstallerException { 562 if (!checkBeforeRemote()) return; 563 BlockGuard.getVmPolicy().onPathAccess(packageDir); 564 try { 565 mInstalld.rmPackageDir(packageDir); 566 } catch (Exception e) { 567 throw InstallerException.from(e); 568 } 569 } 570 clearAppProfiles(String packageName, String profileName)571 public void clearAppProfiles(String packageName, String profileName) throws InstallerException { 572 if (!checkBeforeRemote()) return; 573 try { 574 mInstalld.clearAppProfiles(packageName, profileName); 575 } catch (Exception e) { 576 throw InstallerException.from(e); 577 } 578 } 579 destroyAppProfiles(String packageName)580 public void destroyAppProfiles(String packageName) throws InstallerException { 581 if (!checkBeforeRemote()) return; 582 try { 583 mInstalld.destroyAppProfiles(packageName); 584 } catch (Exception e) { 585 throw InstallerException.from(e); 586 } 587 } 588 createUserData(String uuid, int userId, int userSerial, int flags)589 public void createUserData(String uuid, int userId, int userSerial, int flags) 590 throws InstallerException { 591 if (!checkBeforeRemote()) return; 592 try { 593 mInstalld.createUserData(uuid, userId, userSerial, flags); 594 } catch (Exception e) { 595 throw InstallerException.from(e); 596 } 597 } 598 destroyUserData(String uuid, int userId, int flags)599 public void destroyUserData(String uuid, int userId, int flags) throws InstallerException { 600 if (!checkBeforeRemote()) return; 601 try { 602 mInstalld.destroyUserData(uuid, userId, flags); 603 } catch (Exception e) { 604 throw InstallerException.from(e); 605 } 606 } 607 freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags)608 public void freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags) 609 throws InstallerException { 610 if (!checkBeforeRemote()) return; 611 try { 612 mInstalld.freeCache(uuid, targetFreeBytes, cacheReservedBytes, flags); 613 } catch (Exception e) { 614 throw InstallerException.from(e); 615 } 616 } 617 618 /** 619 * Links the 32 bit native library directory in an application's data 620 * directory to the real location for backward compatibility. Note that no 621 * such symlink is created for 64 bit shared libraries. 622 */ linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32, int userId)623 public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32, 624 int userId) throws InstallerException { 625 if (!checkBeforeRemote()) return; 626 BlockGuard.getVmPolicy().onPathAccess(nativeLibPath32); 627 try { 628 mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId); 629 } catch (Exception e) { 630 throw InstallerException.from(e); 631 } 632 } 633 createOatDir(String oatDir, String dexInstructionSet)634 public void createOatDir(String oatDir, String dexInstructionSet) 635 throws InstallerException { 636 if (!checkBeforeRemote()) return; 637 try { 638 mInstalld.createOatDir(oatDir, dexInstructionSet); 639 } catch (Exception e) { 640 throw InstallerException.from(e); 641 } 642 } 643 linkFile(String relativePath, String fromBase, String toBase)644 public void linkFile(String relativePath, String fromBase, String toBase) 645 throws InstallerException { 646 if (!checkBeforeRemote()) return; 647 BlockGuard.getVmPolicy().onPathAccess(fromBase); 648 BlockGuard.getVmPolicy().onPathAccess(toBase); 649 try { 650 mInstalld.linkFile(relativePath, fromBase, toBase); 651 } catch (Exception e) { 652 throw InstallerException.from(e); 653 } 654 } 655 moveAb(String apkPath, String instructionSet, String outputPath)656 public void moveAb(String apkPath, String instructionSet, String outputPath) 657 throws InstallerException { 658 if (!checkBeforeRemote()) return; 659 BlockGuard.getVmPolicy().onPathAccess(apkPath); 660 BlockGuard.getVmPolicy().onPathAccess(outputPath); 661 try { 662 mInstalld.moveAb(apkPath, instructionSet, outputPath); 663 } catch (Exception e) { 664 throw InstallerException.from(e); 665 } 666 } 667 668 /** 669 * Deletes the optimized artifacts generated by ART and returns the number 670 * of freed bytes. 671 */ deleteOdex(String apkPath, String instructionSet, String outputPath)672 public long deleteOdex(String apkPath, String instructionSet, String outputPath) 673 throws InstallerException { 674 if (!checkBeforeRemote()) return -1; 675 BlockGuard.getVmPolicy().onPathAccess(apkPath); 676 BlockGuard.getVmPolicy().onPathAccess(outputPath); 677 try { 678 return mInstalld.deleteOdex(apkPath, instructionSet, outputPath); 679 } catch (Exception e) { 680 throw InstallerException.from(e); 681 } 682 } 683 installApkVerity(String filePath, FileDescriptor verityInput, int contentSize)684 public void installApkVerity(String filePath, FileDescriptor verityInput, int contentSize) 685 throws InstallerException { 686 if (!checkBeforeRemote()) return; 687 BlockGuard.getVmPolicy().onPathAccess(filePath); 688 try { 689 mInstalld.installApkVerity(filePath, verityInput, contentSize); 690 } catch (Exception e) { 691 throw InstallerException.from(e); 692 } 693 } 694 assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash)695 public void assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash) 696 throws InstallerException { 697 if (!checkBeforeRemote()) return; 698 BlockGuard.getVmPolicy().onPathAccess(filePath); 699 try { 700 mInstalld.assertFsverityRootHashMatches(filePath, expectedHash); 701 } catch (Exception e) { 702 throw InstallerException.from(e); 703 } 704 } 705 reconcileSecondaryDexFile(String apkPath, String packageName, int uid, String[] isas, @Nullable String volumeUuid, int flags)706 public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid, 707 String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException { 708 for (int i = 0; i < isas.length; i++) { 709 assertValidInstructionSet(isas[i]); 710 } 711 if (!checkBeforeRemote()) return false; 712 BlockGuard.getVmPolicy().onPathAccess(apkPath); 713 try { 714 return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas, 715 volumeUuid, flags); 716 } catch (Exception e) { 717 throw InstallerException.from(e); 718 } 719 } 720 hashSecondaryDexFile(String dexPath, String packageName, int uid, @Nullable String volumeUuid, int flags)721 public byte[] hashSecondaryDexFile(String dexPath, String packageName, int uid, 722 @Nullable String volumeUuid, int flags) throws InstallerException { 723 if (!checkBeforeRemote()) return new byte[0]; 724 BlockGuard.getVmPolicy().onPathAccess(dexPath); 725 try { 726 return mInstalld.hashSecondaryDexFile(dexPath, packageName, uid, volumeUuid, flags); 727 } catch (Exception e) { 728 throw InstallerException.from(e); 729 } 730 } 731 createProfileSnapshot(int appId, String packageName, String profileName, String classpath)732 public boolean createProfileSnapshot(int appId, String packageName, String profileName, 733 String classpath) throws InstallerException { 734 if (!checkBeforeRemote()) return false; 735 try { 736 return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath); 737 } catch (Exception e) { 738 throw InstallerException.from(e); 739 } 740 } 741 destroyProfileSnapshot(String packageName, String profileName)742 public void destroyProfileSnapshot(String packageName, String profileName) 743 throws InstallerException { 744 if (!checkBeforeRemote()) return; 745 try { 746 mInstalld.destroyProfileSnapshot(packageName, profileName); 747 } catch (Exception e) { 748 throw InstallerException.from(e); 749 } 750 } 751 invalidateMounts()752 public void invalidateMounts() throws InstallerException { 753 if (!checkBeforeRemote()) return; 754 try { 755 mInstalld.invalidateMounts(); 756 } catch (Exception e) { 757 throw InstallerException.from(e); 758 } 759 } 760 isQuotaSupported(String volumeUuid)761 public boolean isQuotaSupported(String volumeUuid) throws InstallerException { 762 if (!checkBeforeRemote()) return false; 763 try { 764 return mInstalld.isQuotaSupported(volumeUuid); 765 } catch (Exception e) { 766 throw InstallerException.from(e); 767 } 768 } 769 770 /** 771 * Bind mount private volume CE and DE mirror storage. 772 */ tryMountDataMirror(String volumeUuid)773 public void tryMountDataMirror(String volumeUuid) throws InstallerException { 774 if (!checkBeforeRemote()) return; 775 try { 776 mInstalld.tryMountDataMirror(volumeUuid); 777 } catch (Exception e) { 778 throw InstallerException.from(e); 779 } 780 } 781 782 /** 783 * Unmount private volume CE and DE mirror storage. 784 */ onPrivateVolumeRemoved(String volumeUuid)785 public void onPrivateVolumeRemoved(String volumeUuid) throws InstallerException { 786 if (!checkBeforeRemote()) return; 787 try { 788 mInstalld.onPrivateVolumeRemoved(volumeUuid); 789 } catch (Exception e) { 790 throw InstallerException.from(e); 791 } 792 } 793 prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId, String profileName, String codePath, String dexMetadataPath)794 public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId, 795 String profileName, String codePath, String dexMetadataPath) throws InstallerException { 796 if (!checkBeforeRemote()) return false; 797 BlockGuard.getVmPolicy().onPathAccess(codePath); 798 BlockGuard.getVmPolicy().onPathAccess(dexMetadataPath); 799 try { 800 return mInstalld.prepareAppProfile(pkg, userId, appId, profileName, codePath, 801 dexMetadataPath); 802 } catch (Exception e) { 803 throw InstallerException.from(e); 804 } 805 } 806 807 /** 808 * Snapshots user data of the given package. 809 * 810 * @param pkg name of the package to snapshot user data for. 811 * @param userId id of the user whose data to snapshot. 812 * @param snapshotId id of this snapshot. 813 * @param storageFlags flags controlling which data (CE or DE) to snapshot. 814 * 815 * @return {@code true} if the snapshot was taken successfully, or {@code false} if a remote 816 * call shouldn't be continued. See {@link #checkBeforeRemote}. 817 * 818 * @throws InstallerException if failed to snapshot user data. 819 */ snapshotAppData(String pkg, @UserIdInt int userId, int snapshotId, int storageFlags)820 public boolean snapshotAppData(String pkg, @UserIdInt int userId, int snapshotId, 821 int storageFlags) throws InstallerException { 822 if (!checkBeforeRemote()) return false; 823 824 try { 825 mInstalld.snapshotAppData(null, pkg, userId, snapshotId, storageFlags); 826 return true; 827 } catch (Exception e) { 828 throw InstallerException.from(e); 829 } 830 } 831 832 /** 833 * Restores user data snapshot of the given package. 834 * 835 * @param pkg name of the package to restore user data for. 836 * @param appId id of the package to restore user data for. 837 * @param userId id of the user whose data to restore. 838 * @param snapshotId id of the snapshot to restore. 839 * @param storageFlags flags controlling which data (CE or DE) to restore. 840 * 841 * @return {@code true} if user data restore was successful, or {@code false} if a remote call 842 * shouldn't be continued. See {@link #checkBeforeRemote}. 843 * 844 * @throws InstallerException if failed to restore user data. 845 */ restoreAppDataSnapshot(String pkg, @AppIdInt int appId, String seInfo, @UserIdInt int userId, int snapshotId, int storageFlags)846 public boolean restoreAppDataSnapshot(String pkg, @AppIdInt int appId, String seInfo, 847 @UserIdInt int userId, int snapshotId, int storageFlags) throws InstallerException { 848 if (!checkBeforeRemote()) return false; 849 850 try { 851 mInstalld.restoreAppDataSnapshot(null, pkg, appId, seInfo, userId, snapshotId, 852 storageFlags); 853 return true; 854 } catch (Exception e) { 855 throw InstallerException.from(e); 856 } 857 } 858 859 /** 860 * Deletes user data snapshot of the given package. 861 * 862 * @param pkg name of the package to delete user data snapshot for. 863 * @param userId id of the user whose user data snapshot to delete. 864 * @param snapshotId id of the snapshot to delete. 865 * @param storageFlags flags controlling which user data snapshot (CE or DE) to delete. 866 * 867 * @return {@code true} if user data snapshot was successfully deleted, or {@code false} if a 868 * remote call shouldn't be continued. See {@link #checkBeforeRemote}. 869 * 870 * @throws InstallerException if failed to delete user data snapshot. 871 */ destroyAppDataSnapshot(String pkg, @UserIdInt int userId, int snapshotId, int storageFlags)872 public boolean destroyAppDataSnapshot(String pkg, @UserIdInt int userId, 873 int snapshotId, int storageFlags) throws InstallerException { 874 if (!checkBeforeRemote()) return false; 875 876 try { 877 mInstalld.destroyAppDataSnapshot(null, pkg, userId, 0, snapshotId, storageFlags); 878 return true; 879 } catch (Exception e) { 880 throw InstallerException.from(e); 881 } 882 } 883 884 /** 885 * Deletes all snapshots of credential encrypted user data, where the snapshot id is not 886 * included in {@code retainSnapshotIds}. 887 * 888 * @param userId id of the user whose user data snapshots to delete. 889 * @param retainSnapshotIds ids of the snapshots that should not be deleted. 890 * 891 * @return {@code true} if the operation was successful, or {@code false} if a remote call 892 * shouldn't be continued. See {@link #checkBeforeRemote}. 893 * 894 * @throws InstallerException if failed to delete user data snapshot. 895 */ destroyCeSnapshotsNotSpecified(@serIdInt int userId, int[] retainSnapshotIds)896 public boolean destroyCeSnapshotsNotSpecified(@UserIdInt int userId, 897 int[] retainSnapshotIds) throws InstallerException { 898 if (!checkBeforeRemote()) return false; 899 900 try { 901 mInstalld.destroyCeSnapshotsNotSpecified(null, userId, retainSnapshotIds); 902 return true; 903 } catch (Exception e) { 904 throw InstallerException.from(e); 905 } 906 } 907 908 /** 909 * Migrates obb data from its legacy location {@code /data/media/obb} to 910 * {@code /data/media/0/Android/obb}. This call is idempotent and a fast no-op if data has 911 * already been migrated. 912 * 913 * @throws InstallerException if an error occurs. 914 */ migrateLegacyObbData()915 public boolean migrateLegacyObbData() throws InstallerException { 916 if (!checkBeforeRemote()) return false; 917 918 try { 919 mInstalld.migrateLegacyObbData(); 920 return true; 921 } catch (Exception e) { 922 throw InstallerException.from(e); 923 } 924 } 925 assertValidInstructionSet(String instructionSet)926 private static void assertValidInstructionSet(String instructionSet) 927 throws InstallerException { 928 for (String abi : Build.SUPPORTED_ABIS) { 929 if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) { 930 return; 931 } 932 } 933 throw new InstallerException("Invalid instruction set: " + instructionSet); 934 } 935 compileLayouts(String apkPath, String packageName, String outDexFile, int uid)936 public boolean compileLayouts(String apkPath, String packageName, String outDexFile, int uid) { 937 try { 938 return mInstalld.compileLayouts(apkPath, packageName, outDexFile, uid); 939 } catch (RemoteException e) { 940 return false; 941 } 942 } 943 944 public static class InstallerException extends Exception { InstallerException(String detailMessage)945 public InstallerException(String detailMessage) { 946 super(detailMessage); 947 } 948 from(Exception e)949 public static InstallerException from(Exception e) throws InstallerException { 950 throw new InstallerException(e.toString()); 951 } 952 } 953 } 954