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