Installer.java revision cccad1971e4f04db7c8db8b0a9d6afd95937fc5e
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 17package com.android.server.pm; 18 19import android.annotation.AppIdInt; 20import android.annotation.NonNull; 21import android.annotation.Nullable; 22import android.annotation.UserIdInt; 23import android.content.Context; 24import android.content.pm.PackageStats; 25import android.os.Build; 26import android.os.IBinder; 27import android.os.IBinder.DeathRecipient; 28import android.os.IInstalld; 29import android.os.RemoteException; 30import android.os.ServiceManager; 31import android.text.format.DateUtils; 32import android.util.Slog; 33 34import com.android.internal.os.BackgroundThread; 35import com.android.server.SystemService; 36 37import dalvik.system.VMRuntime; 38 39import java.io.FileDescriptor; 40 41public class Installer extends SystemService { 42 private static final String TAG = "Installer"; 43 44 /* *************************************************************************** 45 * IMPORTANT: These values are passed to native code. Keep them in sync with 46 * frameworks/native/cmds/installd/installd.h 47 * **************************************************************************/ 48 /** Application should be visible to everyone */ 49 public static final int DEXOPT_PUBLIC = 1 << 1; 50 /** Application wants to allow debugging of its code */ 51 public static final int DEXOPT_DEBUGGABLE = 1 << 2; 52 /** The system boot has finished */ 53 public static final int DEXOPT_BOOTCOMPLETE = 1 << 3; 54 /** Hint that the dexopt type is profile-guided. */ 55 public static final int DEXOPT_PROFILE_GUIDED = 1 << 4; 56 /** The compilation is for a secondary dex file. */ 57 public static final int DEXOPT_SECONDARY_DEX = 1 << 5; 58 /** Ignore the result of dexoptNeeded and force compilation. */ 59 public static final int DEXOPT_FORCE = 1 << 6; 60 /** Indicates that the dex file passed to dexopt in on CE storage. */ 61 public static final int DEXOPT_STORAGE_CE = 1 << 7; 62 /** Indicates that the dex file passed to dexopt in on DE storage. */ 63 public static final int DEXOPT_STORAGE_DE = 1 << 8; 64 /** Indicates that dexopt is invoked from the background service. */ 65 public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9; 66 /** Indicates that dexopt should restrict access to private APIs. */ 67 public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10; 68 /** Indicates that dexopt should convert to CompactDex. */ 69 public static final int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11; 70 71 // NOTE: keep in sync with installd 72 public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8; 73 public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9; 74 public static final int FLAG_USE_QUOTA = 1 << 12; 75 public static final int FLAG_FREE_CACHE_V2 = 1 << 13; 76 public static final int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14; 77 public static final int FLAG_FREE_CACHE_NOOP = 1 << 15; 78 public static final int FLAG_FORCE = 1 << 16; 79 80 private final boolean mIsolated; 81 82 private volatile IInstalld mInstalld; 83 private volatile Object mWarnIfHeld; 84 85 public Installer(Context context) { 86 this(context, false); 87 } 88 89 /** 90 * @param isolated indicates if this object should <em>not</em> connect to 91 * the real {@code installd}. All remote calls will be ignored 92 * unless you extend this class and intercept them. 93 */ 94 public Installer(Context context, boolean isolated) { 95 super(context); 96 mIsolated = isolated; 97 } 98 99 /** 100 * Yell loudly if someone tries making future calls while holding a lock on 101 * the given object. 102 */ 103 public void setWarnIfHeld(Object warnIfHeld) { 104 mWarnIfHeld = warnIfHeld; 105 } 106 107 @Override 108 public void onStart() { 109 if (mIsolated) { 110 mInstalld = null; 111 } else { 112 connect(); 113 } 114 } 115 116 private void connect() { 117 IBinder binder = ServiceManager.getService("installd"); 118 if (binder != null) { 119 try { 120 binder.linkToDeath(new DeathRecipient() { 121 @Override 122 public void binderDied() { 123 Slog.w(TAG, "installd died; reconnecting"); 124 connect(); 125 } 126 }, 0); 127 } catch (RemoteException e) { 128 binder = null; 129 } 130 } 131 132 if (binder != null) { 133 mInstalld = IInstalld.Stub.asInterface(binder); 134 try { 135 invalidateMounts(); 136 } catch (InstallerException ignored) { 137 } 138 } else { 139 Slog.w(TAG, "installd not found; trying again"); 140 BackgroundThread.getHandler().postDelayed(() -> { 141 connect(); 142 }, DateUtils.SECOND_IN_MILLIS); 143 } 144 } 145 146 /** 147 * Do several pre-flight checks before making a remote call. 148 * 149 * @return if the remote call should continue. 150 */ 151 private boolean checkBeforeRemote() { 152 if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) { 153 Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" 154 + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable()); 155 } 156 if (mIsolated) { 157 Slog.i(TAG, "Ignoring request because this installer is isolated"); 158 return false; 159 } else { 160 return true; 161 } 162 } 163 164 public long createAppData(String uuid, String packageName, int userId, int flags, int appId, 165 String seInfo, int targetSdkVersion) throws InstallerException { 166 if (!checkBeforeRemote()) return -1; 167 try { 168 return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo, 169 targetSdkVersion); 170 } catch (Exception e) { 171 throw InstallerException.from(e); 172 } 173 } 174 175 public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, 176 String seInfo) throws InstallerException { 177 if (!checkBeforeRemote()) return; 178 try { 179 mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo); 180 } catch (Exception e) { 181 throw InstallerException.from(e); 182 } 183 } 184 185 public void migrateAppData(String uuid, String packageName, int userId, int flags) 186 throws InstallerException { 187 if (!checkBeforeRemote()) return; 188 try { 189 mInstalld.migrateAppData(uuid, packageName, userId, flags); 190 } catch (Exception e) { 191 throw InstallerException.from(e); 192 } 193 } 194 195 public void clearAppData(String uuid, String packageName, int userId, int flags, 196 long ceDataInode) throws InstallerException { 197 if (!checkBeforeRemote()) return; 198 try { 199 mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode); 200 } catch (Exception e) { 201 throw InstallerException.from(e); 202 } 203 } 204 205 public void destroyAppData(String uuid, String packageName, int userId, int flags, 206 long ceDataInode) throws InstallerException { 207 if (!checkBeforeRemote()) return; 208 try { 209 mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode); 210 } catch (Exception e) { 211 throw InstallerException.from(e); 212 } 213 } 214 215 public void fixupAppData(String uuid, int flags) throws InstallerException { 216 if (!checkBeforeRemote()) return; 217 try { 218 mInstalld.fixupAppData(uuid, flags); 219 } catch (Exception e) { 220 throw InstallerException.from(e); 221 } 222 } 223 224 public void moveCompleteApp(String fromUuid, String toUuid, String packageName, 225 String dataAppName, int appId, String seInfo, int targetSdkVersion) 226 throws InstallerException { 227 if (!checkBeforeRemote()) return; 228 try { 229 mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo, 230 targetSdkVersion); 231 } catch (Exception e) { 232 throw InstallerException.from(e); 233 } 234 } 235 236 public void getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId, 237 long[] ceDataInodes, String[] codePaths, PackageStats stats) 238 throws InstallerException { 239 if (!checkBeforeRemote()) return; 240 try { 241 final long[] res = mInstalld.getAppSize(uuid, packageNames, userId, flags, 242 appId, ceDataInodes, codePaths); 243 stats.codeSize += res[0]; 244 stats.dataSize += res[1]; 245 stats.cacheSize += res[2]; 246 stats.externalCodeSize += res[3]; 247 stats.externalDataSize += res[4]; 248 stats.externalCacheSize += res[5]; 249 } catch (Exception e) { 250 throw InstallerException.from(e); 251 } 252 } 253 254 public void getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats) 255 throws InstallerException { 256 if (!checkBeforeRemote()) return; 257 try { 258 final long[] res = mInstalld.getUserSize(uuid, userId, flags, appIds); 259 stats.codeSize += res[0]; 260 stats.dataSize += res[1]; 261 stats.cacheSize += res[2]; 262 stats.externalCodeSize += res[3]; 263 stats.externalDataSize += res[4]; 264 stats.externalCacheSize += res[5]; 265 } catch (Exception e) { 266 throw InstallerException.from(e); 267 } 268 } 269 270 public long[] getExternalSize(String uuid, int userId, int flags, int[] appIds) 271 throws InstallerException { 272 if (!checkBeforeRemote()) return new long[6]; 273 try { 274 return mInstalld.getExternalSize(uuid, userId, flags, appIds); 275 } catch (Exception e) { 276 throw InstallerException.from(e); 277 } 278 } 279 280 public void setAppQuota(String uuid, int userId, int appId, long cacheQuota) 281 throws InstallerException { 282 if (!checkBeforeRemote()) return; 283 try { 284 mInstalld.setAppQuota(uuid, userId, appId, cacheQuota); 285 } catch (Exception e) { 286 throw InstallerException.from(e); 287 } 288 } 289 290 public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet, 291 int dexoptNeeded, @Nullable String outputPath, int dexFlags, 292 String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries, 293 @Nullable String seInfo, boolean downgrade, int targetSdkVersion, 294 @Nullable String profileName, @Nullable String dexMetadataPath, 295 @Nullable String compilationReason) throws InstallerException { 296 assertValidInstructionSet(instructionSet); 297 if (!checkBeforeRemote()) return; 298 try { 299 mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath, 300 dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade, 301 targetSdkVersion, profileName, dexMetadataPath, compilationReason); 302 } catch (Exception e) { 303 throw InstallerException.from(e); 304 } 305 } 306 307 public boolean mergeProfiles(int uid, String packageName, String profileName) 308 throws InstallerException { 309 if (!checkBeforeRemote()) return false; 310 try { 311 return mInstalld.mergeProfiles(uid, packageName, profileName); 312 } catch (Exception e) { 313 throw InstallerException.from(e); 314 } 315 } 316 317 public boolean dumpProfiles(int uid, String packageName, String profileName, String codePath) 318 throws InstallerException { 319 if (!checkBeforeRemote()) return false; 320 try { 321 return mInstalld.dumpProfiles(uid, packageName, profileName, codePath); 322 } catch (Exception e) { 323 throw InstallerException.from(e); 324 } 325 } 326 327 public boolean copySystemProfile(String systemProfile, int uid, String packageName, 328 String profileName) throws InstallerException { 329 if (!checkBeforeRemote()) return false; 330 try { 331 return mInstalld.copySystemProfile(systemProfile, uid, packageName, profileName); 332 } catch (Exception e) { 333 throw InstallerException.from(e); 334 } 335 } 336 337 public void idmap(String targetApkPath, String overlayApkPath, int uid) 338 throws InstallerException { 339 if (!checkBeforeRemote()) return; 340 try { 341 mInstalld.idmap(targetApkPath, overlayApkPath, uid); 342 } catch (Exception e) { 343 throw InstallerException.from(e); 344 } 345 } 346 347 public void removeIdmap(String overlayApkPath) throws InstallerException { 348 if (!checkBeforeRemote()) return; 349 try { 350 mInstalld.removeIdmap(overlayApkPath); 351 } catch (Exception e) { 352 throw InstallerException.from(e); 353 } 354 } 355 356 public void rmdex(String codePath, String instructionSet) throws InstallerException { 357 assertValidInstructionSet(instructionSet); 358 if (!checkBeforeRemote()) return; 359 try { 360 mInstalld.rmdex(codePath, instructionSet); 361 } catch (Exception e) { 362 throw InstallerException.from(e); 363 } 364 } 365 366 public void rmPackageDir(String packageDir) throws InstallerException { 367 if (!checkBeforeRemote()) return; 368 try { 369 mInstalld.rmPackageDir(packageDir); 370 } catch (Exception e) { 371 throw InstallerException.from(e); 372 } 373 } 374 375 public void clearAppProfiles(String packageName, String profileName) throws InstallerException { 376 if (!checkBeforeRemote()) return; 377 try { 378 mInstalld.clearAppProfiles(packageName, profileName); 379 } catch (Exception e) { 380 throw InstallerException.from(e); 381 } 382 } 383 384 public void destroyAppProfiles(String packageName) throws InstallerException { 385 if (!checkBeforeRemote()) return; 386 try { 387 mInstalld.destroyAppProfiles(packageName); 388 } catch (Exception e) { 389 throw InstallerException.from(e); 390 } 391 } 392 393 public void createUserData(String uuid, int userId, int userSerial, int flags) 394 throws InstallerException { 395 if (!checkBeforeRemote()) return; 396 try { 397 mInstalld.createUserData(uuid, userId, userSerial, flags); 398 } catch (Exception e) { 399 throw InstallerException.from(e); 400 } 401 } 402 403 public void destroyUserData(String uuid, int userId, int flags) throws InstallerException { 404 if (!checkBeforeRemote()) return; 405 try { 406 mInstalld.destroyUserData(uuid, userId, flags); 407 } catch (Exception e) { 408 throw InstallerException.from(e); 409 } 410 } 411 412 public void markBootComplete(String instructionSet) throws InstallerException { 413 assertValidInstructionSet(instructionSet); 414 if (!checkBeforeRemote()) return; 415 try { 416 mInstalld.markBootComplete(instructionSet); 417 } catch (Exception e) { 418 throw InstallerException.from(e); 419 } 420 } 421 422 public void freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags) 423 throws InstallerException { 424 if (!checkBeforeRemote()) return; 425 try { 426 mInstalld.freeCache(uuid, targetFreeBytes, cacheReservedBytes, flags); 427 } catch (Exception e) { 428 throw InstallerException.from(e); 429 } 430 } 431 432 /** 433 * Links the 32 bit native library directory in an application's data 434 * directory to the real location for backward compatibility. Note that no 435 * such symlink is created for 64 bit shared libraries. 436 */ 437 public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32, 438 int userId) throws InstallerException { 439 if (!checkBeforeRemote()) return; 440 try { 441 mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId); 442 } catch (Exception e) { 443 throw InstallerException.from(e); 444 } 445 } 446 447 public void createOatDir(String oatDir, String dexInstructionSet) 448 throws InstallerException { 449 if (!checkBeforeRemote()) return; 450 try { 451 mInstalld.createOatDir(oatDir, dexInstructionSet); 452 } catch (Exception e) { 453 throw InstallerException.from(e); 454 } 455 } 456 457 public void linkFile(String relativePath, String fromBase, String toBase) 458 throws InstallerException { 459 if (!checkBeforeRemote()) return; 460 try { 461 mInstalld.linkFile(relativePath, fromBase, toBase); 462 } catch (Exception e) { 463 throw InstallerException.from(e); 464 } 465 } 466 467 public void moveAb(String apkPath, String instructionSet, String outputPath) 468 throws InstallerException { 469 if (!checkBeforeRemote()) return; 470 try { 471 mInstalld.moveAb(apkPath, instructionSet, outputPath); 472 } catch (Exception e) { 473 throw InstallerException.from(e); 474 } 475 } 476 477 public void deleteOdex(String apkPath, String instructionSet, String outputPath) 478 throws InstallerException { 479 if (!checkBeforeRemote()) return; 480 try { 481 mInstalld.deleteOdex(apkPath, instructionSet, outputPath); 482 } catch (Exception e) { 483 throw InstallerException.from(e); 484 } 485 } 486 487 public void installApkVerity(String filePath, FileDescriptor verityInput, int contentSize) 488 throws InstallerException { 489 if (!checkBeforeRemote()) return; 490 try { 491 mInstalld.installApkVerity(filePath, verityInput, contentSize); 492 } catch (Exception e) { 493 throw InstallerException.from(e); 494 } 495 } 496 497 public void assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash) 498 throws InstallerException { 499 if (!checkBeforeRemote()) return; 500 try { 501 mInstalld.assertFsverityRootHashMatches(filePath, expectedHash); 502 } catch (Exception e) { 503 throw InstallerException.from(e); 504 } 505 } 506 507 public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid, 508 String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException { 509 for (int i = 0; i < isas.length; i++) { 510 assertValidInstructionSet(isas[i]); 511 } 512 if (!checkBeforeRemote()) return false; 513 try { 514 return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas, 515 volumeUuid, flags); 516 } catch (Exception e) { 517 throw InstallerException.from(e); 518 } 519 } 520 521 public byte[] hashSecondaryDexFile(String dexPath, String packageName, int uid, 522 @Nullable String volumeUuid, int flags) throws InstallerException { 523 if (!checkBeforeRemote()) return new byte[0]; 524 try { 525 return mInstalld.hashSecondaryDexFile(dexPath, packageName, uid, volumeUuid, flags); 526 } catch (Exception e) { 527 throw InstallerException.from(e); 528 } 529 } 530 531 public boolean createProfileSnapshot(int appId, String packageName, String profileName, 532 String classpath) throws InstallerException { 533 if (!checkBeforeRemote()) return false; 534 try { 535 return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath); 536 } catch (Exception e) { 537 throw InstallerException.from(e); 538 } 539 } 540 541 public void destroyProfileSnapshot(String packageName, String profileName) 542 throws InstallerException { 543 if (!checkBeforeRemote()) return; 544 try { 545 mInstalld.destroyProfileSnapshot(packageName, profileName); 546 } catch (Exception e) { 547 throw InstallerException.from(e); 548 } 549 } 550 551 public void invalidateMounts() throws InstallerException { 552 if (!checkBeforeRemote()) return; 553 try { 554 mInstalld.invalidateMounts(); 555 } catch (Exception e) { 556 throw InstallerException.from(e); 557 } 558 } 559 560 public boolean isQuotaSupported(String volumeUuid) throws InstallerException { 561 if (!checkBeforeRemote()) return false; 562 try { 563 return mInstalld.isQuotaSupported(volumeUuid); 564 } catch (Exception e) { 565 throw InstallerException.from(e); 566 } 567 } 568 569 public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId, 570 String profileName, String codePath, String dexMetadataPath) throws InstallerException { 571 if (!checkBeforeRemote()) return false; 572 try { 573 return mInstalld.prepareAppProfile(pkg, userId, appId, profileName, codePath, 574 dexMetadataPath); 575 } catch (Exception e) { 576 throw InstallerException.from(e); 577 } 578 } 579 580 private static void assertValidInstructionSet(String instructionSet) 581 throws InstallerException { 582 for (String abi : Build.SUPPORTED_ABIS) { 583 if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) { 584 return; 585 } 586 } 587 throw new InstallerException("Invalid instruction set: " + instructionSet); 588 } 589 590 public static class InstallerException extends Exception { 591 public InstallerException(String detailMessage) { 592 super(detailMessage); 593 } 594 595 public static InstallerException from(Exception e) throws InstallerException { 596 throw new InstallerException(e.toString()); 597 } 598 } 599} 600