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