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