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