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