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