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 17 package com.android.server.pm; 18 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.content.pm.PackageStats; 22 import android.os.Build; 23 import android.os.IBinder; 24 import android.os.IBinder.DeathRecipient; 25 import android.os.IInstalld; 26 import android.os.RemoteException; 27 import android.os.ServiceManager; 28 import android.text.format.DateUtils; 29 import android.util.Slog; 30 31 import com.android.internal.os.BackgroundThread; 32 import com.android.server.SystemService; 33 34 import dalvik.system.VMRuntime; 35 36 public 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 Installer(Context context)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 */ Installer(Context context, boolean isolated)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 */ setWarnIfHeld(Object warnIfHeld)92 public void setWarnIfHeld(Object warnIfHeld) { 93 mWarnIfHeld = warnIfHeld; 94 } 95 96 @Override onStart()97 public void onStart() { 98 if (mIsolated) { 99 mInstalld = null; 100 } else { 101 connect(); 102 } 103 } 104 connect()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 */ checkBeforeRemote()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 createAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion)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 restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo)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 migrateAppData(String uuid, String packageName, int userId, int flags)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 clearAppData(String uuid, String packageName, int userId, int flags, long ceDataInode)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 destroyAppData(String uuid, String packageName, int userId, int flags, long ceDataInode)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 fixupAppData(String uuid, int flags)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 moveCompleteApp(String fromUuid, String toUuid, String packageName, String dataAppName, int appId, String seInfo, int targetSdkVersion)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 getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId, long[] ceDataInodes, String[] codePaths, PackageStats stats)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 getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats)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 getExternalSize(String uuid, int userId, int flags, int[] appIds)259 public long[] getExternalSize(String uuid, int userId, int flags, int[] appIds) 260 throws InstallerException { 261 if (!checkBeforeRemote()) return new long[4]; 262 try { 263 return mInstalld.getExternalSize(uuid, userId, flags, appIds); 264 } catch (Exception e) { 265 throw InstallerException.from(e); 266 } 267 } 268 setAppQuota(String uuid, int userId, int appId, long cacheQuota)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 dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet, int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries, @Nullable String seInfo)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) 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); 289 } catch (Exception e) { 290 throw InstallerException.from(e); 291 } 292 } 293 mergeProfiles(int uid, String packageName)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 dumpProfiles(int uid, String packageName, String codePaths)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 idmap(String targetApkPath, String overlayApkPath, int uid)313 public void idmap(String targetApkPath, String overlayApkPath, int uid) 314 throws InstallerException { 315 if (!checkBeforeRemote()) return; 316 try { 317 mInstalld.idmap(targetApkPath, overlayApkPath, uid); 318 } catch (Exception e) { 319 throw InstallerException.from(e); 320 } 321 } 322 removeIdmap(String overlayApkPath)323 public void removeIdmap(String overlayApkPath) throws InstallerException { 324 if (!checkBeforeRemote()) return; 325 try { 326 mInstalld.removeIdmap(overlayApkPath); 327 } catch (Exception e) { 328 throw InstallerException.from(e); 329 } 330 } 331 rmdex(String codePath, String instructionSet)332 public void rmdex(String codePath, String instructionSet) throws InstallerException { 333 assertValidInstructionSet(instructionSet); 334 if (!checkBeforeRemote()) return; 335 try { 336 mInstalld.rmdex(codePath, instructionSet); 337 } catch (Exception e) { 338 throw InstallerException.from(e); 339 } 340 } 341 rmPackageDir(String packageDir)342 public void rmPackageDir(String packageDir) throws InstallerException { 343 if (!checkBeforeRemote()) return; 344 try { 345 mInstalld.rmPackageDir(packageDir); 346 } catch (Exception e) { 347 throw InstallerException.from(e); 348 } 349 } 350 clearAppProfiles(String packageName)351 public void clearAppProfiles(String packageName) throws InstallerException { 352 if (!checkBeforeRemote()) return; 353 try { 354 mInstalld.clearAppProfiles(packageName); 355 } catch (Exception e) { 356 throw InstallerException.from(e); 357 } 358 } 359 destroyAppProfiles(String packageName)360 public void destroyAppProfiles(String packageName) throws InstallerException { 361 if (!checkBeforeRemote()) return; 362 try { 363 mInstalld.destroyAppProfiles(packageName); 364 } catch (Exception e) { 365 throw InstallerException.from(e); 366 } 367 } 368 createUserData(String uuid, int userId, int userSerial, int flags)369 public void createUserData(String uuid, int userId, int userSerial, int flags) 370 throws InstallerException { 371 if (!checkBeforeRemote()) return; 372 try { 373 mInstalld.createUserData(uuid, userId, userSerial, flags); 374 } catch (Exception e) { 375 throw InstallerException.from(e); 376 } 377 } 378 destroyUserData(String uuid, int userId, int flags)379 public void destroyUserData(String uuid, int userId, int flags) throws InstallerException { 380 if (!checkBeforeRemote()) return; 381 try { 382 mInstalld.destroyUserData(uuid, userId, flags); 383 } catch (Exception e) { 384 throw InstallerException.from(e); 385 } 386 } 387 markBootComplete(String instructionSet)388 public void markBootComplete(String instructionSet) throws InstallerException { 389 assertValidInstructionSet(instructionSet); 390 if (!checkBeforeRemote()) return; 391 try { 392 mInstalld.markBootComplete(instructionSet); 393 } catch (Exception e) { 394 throw InstallerException.from(e); 395 } 396 } 397 freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags)398 public void freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags) 399 throws InstallerException { 400 if (!checkBeforeRemote()) return; 401 try { 402 mInstalld.freeCache(uuid, targetFreeBytes, cacheReservedBytes, flags); 403 } catch (Exception e) { 404 throw InstallerException.from(e); 405 } 406 } 407 408 /** 409 * Links the 32 bit native library directory in an application's data 410 * directory to the real location for backward compatibility. Note that no 411 * such symlink is created for 64 bit shared libraries. 412 */ linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32, int userId)413 public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32, 414 int userId) throws InstallerException { 415 if (!checkBeforeRemote()) return; 416 try { 417 mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId); 418 } catch (Exception e) { 419 throw InstallerException.from(e); 420 } 421 } 422 createOatDir(String oatDir, String dexInstructionSet)423 public void createOatDir(String oatDir, String dexInstructionSet) 424 throws InstallerException { 425 if (!checkBeforeRemote()) return; 426 try { 427 mInstalld.createOatDir(oatDir, dexInstructionSet); 428 } catch (Exception e) { 429 throw InstallerException.from(e); 430 } 431 } 432 linkFile(String relativePath, String fromBase, String toBase)433 public void linkFile(String relativePath, String fromBase, String toBase) 434 throws InstallerException { 435 if (!checkBeforeRemote()) return; 436 try { 437 mInstalld.linkFile(relativePath, fromBase, toBase); 438 } catch (Exception e) { 439 throw InstallerException.from(e); 440 } 441 } 442 moveAb(String apkPath, String instructionSet, String outputPath)443 public void moveAb(String apkPath, String instructionSet, String outputPath) 444 throws InstallerException { 445 if (!checkBeforeRemote()) return; 446 try { 447 mInstalld.moveAb(apkPath, instructionSet, outputPath); 448 } catch (Exception e) { 449 throw InstallerException.from(e); 450 } 451 } 452 deleteOdex(String apkPath, String instructionSet, String outputPath)453 public void deleteOdex(String apkPath, String instructionSet, String outputPath) 454 throws InstallerException { 455 if (!checkBeforeRemote()) return; 456 try { 457 mInstalld.deleteOdex(apkPath, instructionSet, outputPath); 458 } catch (Exception e) { 459 throw InstallerException.from(e); 460 } 461 } 462 reconcileSecondaryDexFile(String apkPath, String packageName, int uid, String[] isas, @Nullable String volumeUuid, int flags)463 public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid, 464 String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException { 465 for (int i = 0; i < isas.length; i++) { 466 assertValidInstructionSet(isas[i]); 467 } 468 if (!checkBeforeRemote()) return false; 469 try { 470 return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas, 471 volumeUuid, flags); 472 } catch (Exception e) { 473 throw InstallerException.from(e); 474 } 475 } 476 invalidateMounts()477 public void invalidateMounts() throws InstallerException { 478 if (!checkBeforeRemote()) return; 479 try { 480 mInstalld.invalidateMounts(); 481 } catch (Exception e) { 482 throw InstallerException.from(e); 483 } 484 } 485 isQuotaSupported(String volumeUuid)486 public boolean isQuotaSupported(String volumeUuid) throws InstallerException { 487 if (!checkBeforeRemote()) return false; 488 try { 489 return mInstalld.isQuotaSupported(volumeUuid); 490 } catch (Exception e) { 491 throw InstallerException.from(e); 492 } 493 } 494 assertValidInstructionSet(String instructionSet)495 private static void assertValidInstructionSet(String instructionSet) 496 throws InstallerException { 497 for (String abi : Build.SUPPORTED_ABIS) { 498 if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) { 499 return; 500 } 501 } 502 throw new InstallerException("Invalid instruction set: " + instructionSet); 503 } 504 505 public static class InstallerException extends Exception { InstallerException(String detailMessage)506 public InstallerException(String detailMessage) { 507 super(detailMessage); 508 } 509 from(Exception e)510 public static InstallerException from(Exception e) throws InstallerException { 511 throw new InstallerException(e.toString()); 512 } 513 } 514 } 515