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