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