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