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