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