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