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