Installer.java revision 4f05cd8900bfb559d5de58b86fa01f07bddafb2c
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.IInstalld; 24import android.os.RemoteException; 25import android.os.ServiceManager; 26import android.os.ServiceSpecificException; 27import android.util.Slog; 28 29import com.android.server.SystemService; 30 31import dalvik.system.VMRuntime; 32 33public class Installer extends SystemService { 34 private static final String TAG = "Installer"; 35 36 /* *************************************************************************** 37 * IMPORTANT: These values are passed to native code. Keep them in sync with 38 * frameworks/native/cmds/installd/installd.h 39 * **************************************************************************/ 40 /** Application should be visible to everyone */ 41 public static final int DEXOPT_PUBLIC = 1 << 1; 42 /** Application wants to run in VM safe mode */ 43 public static final int DEXOPT_SAFEMODE = 1 << 2; 44 /** Application wants to allow debugging of its code */ 45 public static final int DEXOPT_DEBUGGABLE = 1 << 3; 46 /** The system boot has finished */ 47 public static final int DEXOPT_BOOTCOMPLETE = 1 << 4; 48 /** Hint that the dexopt type is profile-guided. */ 49 public static final int DEXOPT_PROFILE_GUIDED = 1 << 5; 50 51 // NOTE: keep in sync with installd 52 public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8; 53 public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9; 54 55 private final boolean mIsolated; 56 57 // TODO: reconnect if installd restarts 58 private volatile IInstalld mInstalld; 59 private volatile Object mWarnIfHeld; 60 61 public Installer(Context context) { 62 this(context, false); 63 } 64 65 /** 66 * @param isolated indicates if this object should <em>not</em> connect to 67 * the real {@code installd}. All remote calls will be ignored 68 * unless you extend this class and intercept them. 69 */ 70 public Installer(Context context, boolean isolated) { 71 super(context); 72 mIsolated = isolated; 73 } 74 75 /** 76 * Yell loudly if someone tries making future calls while holding a lock on 77 * the given object. 78 */ 79 public void setWarnIfHeld(Object warnIfHeld) { 80 mWarnIfHeld = warnIfHeld; 81 } 82 83 @Override 84 public void onStart() { 85 if (mIsolated) { 86 mInstalld = null; 87 } else { 88 mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd")); 89 } 90 } 91 92 /** 93 * Do several pre-flight checks before making a remote call. 94 * 95 * @return if the remote call should continue. 96 */ 97 private boolean checkBeforeRemote() { 98 if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) { 99 Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" 100 + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable()); 101 } 102 if (mIsolated) { 103 Slog.i(TAG, "Ignoring request because this installer is isolated"); 104 return false; 105 } else { 106 return true; 107 } 108 } 109 110 public void createAppData(String uuid, String packageName, int userId, int flags, int appId, 111 String seInfo, int targetSdkVersion) throws InstallerException { 112 if (!checkBeforeRemote()) return; 113 try { 114 mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo, 115 targetSdkVersion); 116 } catch (RemoteException | ServiceSpecificException e) { 117 throw InstallerException.from(e); 118 } 119 } 120 121 public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, 122 String seInfo) throws InstallerException { 123 if (!checkBeforeRemote()) return; 124 try { 125 mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo); 126 } catch (RemoteException | ServiceSpecificException e) { 127 throw InstallerException.from(e); 128 } 129 } 130 131 public void migrateAppData(String uuid, String packageName, int userId, int flags) 132 throws InstallerException { 133 if (!checkBeforeRemote()) return; 134 try { 135 mInstalld.migrateAppData(uuid, packageName, userId, flags); 136 } catch (RemoteException | ServiceSpecificException e) { 137 throw InstallerException.from(e); 138 } 139 } 140 141 public void clearAppData(String uuid, String packageName, int userId, int flags, 142 long ceDataInode) throws InstallerException { 143 if (!checkBeforeRemote()) return; 144 try { 145 mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode); 146 } catch (RemoteException | ServiceSpecificException e) { 147 throw InstallerException.from(e); 148 } 149 } 150 151 public void destroyAppData(String uuid, String packageName, int userId, int flags, 152 long ceDataInode) throws InstallerException { 153 if (!checkBeforeRemote()) return; 154 try { 155 mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode); 156 } catch (RemoteException | ServiceSpecificException e) { 157 throw InstallerException.from(e); 158 } 159 } 160 161 public void moveCompleteApp(String fromUuid, String toUuid, String packageName, 162 String dataAppName, int appId, String seInfo, int targetSdkVersion) 163 throws InstallerException { 164 if (!checkBeforeRemote()) return; 165 try { 166 mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo, 167 targetSdkVersion); 168 } catch (RemoteException | ServiceSpecificException e) { 169 throw InstallerException.from(e); 170 } 171 } 172 173 public void getAppSize(String uuid, String packageName, int userId, int flags, long ceDataInode, 174 String codePath, PackageStats stats) throws InstallerException { 175 if (!checkBeforeRemote()) return; 176 try { 177 final long[] res = mInstalld.getAppSize(uuid, packageName, userId, flags, ceDataInode, 178 codePath); 179 stats.codeSize += res[0]; 180 stats.dataSize += res[1]; 181 stats.cacheSize += res[2]; 182 } catch (RemoteException | ServiceSpecificException e) { 183 throw InstallerException.from(e); 184 } 185 } 186 187 public long getAppDataInode(String uuid, String packageName, int userId, int flags) 188 throws InstallerException { 189 if (!checkBeforeRemote()) return -1; 190 try { 191 return mInstalld.getAppDataInode(uuid, packageName, userId, flags); 192 } catch (RemoteException | ServiceSpecificException e) { 193 throw InstallerException.from(e); 194 } 195 } 196 197 public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet, 198 int dexoptNeeded, @Nullable String outputPath, int dexFlags, 199 String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries) 200 throws InstallerException { 201 assertValidInstructionSet(instructionSet); 202 if (!checkBeforeRemote()) return; 203 try { 204 mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath, 205 dexFlags, compilerFilter, volumeUuid, sharedLibraries); 206 } catch (RemoteException | ServiceSpecificException e) { 207 throw InstallerException.from(e); 208 } 209 } 210 211 public boolean mergeProfiles(int uid, String packageName) throws InstallerException { 212 if (!checkBeforeRemote()) return false; 213 try { 214 return mInstalld.mergeProfiles(uid, packageName); 215 } catch (RemoteException | ServiceSpecificException e) { 216 throw InstallerException.from(e); 217 } 218 } 219 220 public boolean dumpProfiles(int uid, String packageName, String codePaths) 221 throws InstallerException { 222 if (!checkBeforeRemote()) return false; 223 try { 224 return mInstalld.dumpProfiles(uid, packageName, codePaths); 225 } catch (RemoteException | ServiceSpecificException e) { 226 throw InstallerException.from(e); 227 } 228 } 229 230 public void idmap(String targetApkPath, String overlayApkPath, int uid) 231 throws InstallerException { 232 if (!checkBeforeRemote()) return; 233 try { 234 mInstalld.idmap(targetApkPath, overlayApkPath, uid); 235 } catch (RemoteException | ServiceSpecificException e) { 236 throw InstallerException.from(e); 237 } 238 } 239 240 public void rmdex(String codePath, String instructionSet) throws InstallerException { 241 assertValidInstructionSet(instructionSet); 242 if (!checkBeforeRemote()) return; 243 try { 244 mInstalld.rmdex(codePath, instructionSet); 245 } catch (RemoteException | ServiceSpecificException e) { 246 throw InstallerException.from(e); 247 } 248 } 249 250 public void rmPackageDir(String packageDir) throws InstallerException { 251 if (!checkBeforeRemote()) return; 252 try { 253 mInstalld.rmPackageDir(packageDir); 254 } catch (RemoteException | ServiceSpecificException e) { 255 throw InstallerException.from(e); 256 } 257 } 258 259 public void clearAppProfiles(String packageName) throws InstallerException { 260 if (!checkBeforeRemote()) return; 261 try { 262 mInstalld.clearAppProfiles(packageName); 263 } catch (RemoteException | ServiceSpecificException e) { 264 throw InstallerException.from(e); 265 } 266 } 267 268 public void destroyAppProfiles(String packageName) throws InstallerException { 269 if (!checkBeforeRemote()) return; 270 try { 271 mInstalld.destroyAppProfiles(packageName); 272 } catch (RemoteException | ServiceSpecificException e) { 273 throw InstallerException.from(e); 274 } 275 } 276 277 public void createUserData(String uuid, int userId, int userSerial, int flags) 278 throws InstallerException { 279 if (!checkBeforeRemote()) return; 280 try { 281 mInstalld.createUserData(uuid, userId, userSerial, flags); 282 } catch (RemoteException | ServiceSpecificException e) { 283 throw InstallerException.from(e); 284 } 285 } 286 287 public void destroyUserData(String uuid, int userId, int flags) throws InstallerException { 288 if (!checkBeforeRemote()) return; 289 try { 290 mInstalld.destroyUserData(uuid, userId, flags); 291 } catch (RemoteException | ServiceSpecificException e) { 292 throw InstallerException.from(e); 293 } 294 } 295 296 public void markBootComplete(String instructionSet) throws InstallerException { 297 assertValidInstructionSet(instructionSet); 298 if (!checkBeforeRemote()) return; 299 try { 300 mInstalld.markBootComplete(instructionSet); 301 } catch (RemoteException | ServiceSpecificException e) { 302 throw InstallerException.from(e); 303 } 304 } 305 306 public void freeCache(String uuid, long freeStorageSize) throws InstallerException { 307 if (!checkBeforeRemote()) return; 308 try { 309 mInstalld.freeCache(uuid, freeStorageSize); 310 } catch (RemoteException | ServiceSpecificException e) { 311 throw InstallerException.from(e); 312 } 313 } 314 315 /** 316 * Links the 32 bit native library directory in an application's data 317 * directory to the real location for backward compatibility. Note that no 318 * such symlink is created for 64 bit shared libraries. 319 */ 320 public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32, 321 int userId) throws InstallerException { 322 if (!checkBeforeRemote()) return; 323 try { 324 mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId); 325 } catch (RemoteException | ServiceSpecificException e) { 326 throw InstallerException.from(e); 327 } 328 } 329 330 public void createOatDir(String oatDir, String dexInstructionSet) 331 throws InstallerException { 332 if (!checkBeforeRemote()) return; 333 try { 334 mInstalld.createOatDir(oatDir, dexInstructionSet); 335 } catch (RemoteException | ServiceSpecificException e) { 336 throw InstallerException.from(e); 337 } 338 } 339 340 public void linkFile(String relativePath, String fromBase, String toBase) 341 throws InstallerException { 342 if (!checkBeforeRemote()) return; 343 try { 344 mInstalld.linkFile(relativePath, fromBase, toBase); 345 } catch (RemoteException | ServiceSpecificException e) { 346 throw InstallerException.from(e); 347 } 348 } 349 350 public void moveAb(String apkPath, String instructionSet, String outputPath) 351 throws InstallerException { 352 if (!checkBeforeRemote()) return; 353 try { 354 mInstalld.moveAb(apkPath, instructionSet, outputPath); 355 } catch (RemoteException | ServiceSpecificException e) { 356 throw InstallerException.from(e); 357 } 358 } 359 360 public void deleteOdex(String apkPath, String instructionSet, String outputPath) 361 throws InstallerException { 362 if (!checkBeforeRemote()) return; 363 try { 364 mInstalld.deleteOdex(apkPath, instructionSet, outputPath); 365 } catch (RemoteException | ServiceSpecificException e) { 366 throw InstallerException.from(e); 367 } 368 } 369 370 private static void assertValidInstructionSet(String instructionSet) 371 throws InstallerException { 372 for (String abi : Build.SUPPORTED_ABIS) { 373 if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) { 374 return; 375 } 376 } 377 throw new InstallerException("Invalid instruction set: " + instructionSet); 378 } 379 380 public static class InstallerException extends Exception { 381 public InstallerException(String detailMessage) { 382 super(detailMessage); 383 } 384 385 public static InstallerException from(Exception e) throws InstallerException { 386 throw new InstallerException(e.getMessage()); 387 } 388 } 389} 390