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