Installer.java revision 8948c01eb726ec79983472e5597ddac8004f9f44
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.text.TextUtils; 24import android.util.Slog; 25 26import dalvik.system.VMRuntime; 27 28import com.android.internal.os.InstallerConnection; 29import com.android.server.SystemService; 30 31public final class Installer extends SystemService { 32 private static final String TAG = "Installer"; 33 34 /* *************************************************************************** 35 * IMPORTANT: These values are passed to native code. Keep them in sync with 36 * frameworks/native/cmds/installd/installd.h 37 * **************************************************************************/ 38 /** Application should be visible to everyone */ 39 public static final int DEXOPT_PUBLIC = 1 << 1; 40 /** Application wants to run in VM safe mode */ 41 public static final int DEXOPT_SAFEMODE = 1 << 2; 42 /** Application wants to allow debugging of its code */ 43 public static final int DEXOPT_DEBUGGABLE = 1 << 3; 44 /** The system boot has finished */ 45 public static final int DEXOPT_BOOTCOMPLETE = 1 << 4; 46 /** Run the application with the JIT compiler */ 47 public static final int DEXOPT_USEJIT = 1 << 5; 48 49 private final InstallerConnection mInstaller; 50 51 public Installer(Context context) { 52 super(context); 53 mInstaller = new InstallerConnection(); 54 } 55 56 /** 57 * Yell loudly if someone tries making future calls while holding a lock on 58 * the given object. 59 */ 60 public void setWarnIfHeld(Object warnIfHeld) { 61 mInstaller.setWarnIfHeld(warnIfHeld); 62 } 63 64 @Override 65 public void onStart() { 66 Slog.i(TAG, "Waiting for installd to be ready."); 67 mInstaller.waitForConnection(); 68 } 69 70 private static String escapeNull(String arg) { 71 if (TextUtils.isEmpty(arg)) { 72 return "!"; 73 } else { 74 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) { 75 throw new IllegalArgumentException(arg); 76 } 77 return arg; 78 } 79 } 80 81 @Deprecated 82 public int install(String name, int uid, int gid, String seinfo) { 83 return install(null, name, uid, gid, seinfo); 84 } 85 86 public int install(String uuid, String name, int uid, int gid, String seinfo) { 87 StringBuilder builder = new StringBuilder("install"); 88 builder.append(' '); 89 builder.append(escapeNull(uuid)); 90 builder.append(' '); 91 builder.append(name); 92 builder.append(' '); 93 builder.append(uid); 94 builder.append(' '); 95 builder.append(gid); 96 builder.append(' '); 97 builder.append(seinfo != null ? seinfo : "!"); 98 return mInstaller.execute(builder.toString()); 99 } 100 101 public int dexopt(String apkPath, int uid, String instructionSet, 102 int dexoptNeeded, int dexFlags) { 103 if (!isValidInstructionSet(instructionSet)) { 104 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 105 return -1; 106 } 107 108 return mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags); 109 } 110 111 public int dexopt(String apkPath, int uid, String pkgName, String instructionSet, 112 int dexoptNeeded, @Nullable String outputPath, int dexFlags) { 113 if (!isValidInstructionSet(instructionSet)) { 114 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 115 return -1; 116 } 117 return mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, 118 outputPath, dexFlags); 119 } 120 121 public int idmap(String targetApkPath, String overlayApkPath, int uid) { 122 StringBuilder builder = new StringBuilder("idmap"); 123 builder.append(' '); 124 builder.append(targetApkPath); 125 builder.append(' '); 126 builder.append(overlayApkPath); 127 builder.append(' '); 128 builder.append(uid); 129 return mInstaller.execute(builder.toString()); 130 } 131 132 public int movedex(String srcPath, String dstPath, String instructionSet) { 133 if (!isValidInstructionSet(instructionSet)) { 134 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 135 return -1; 136 } 137 138 StringBuilder builder = new StringBuilder("movedex"); 139 builder.append(' '); 140 builder.append(srcPath); 141 builder.append(' '); 142 builder.append(dstPath); 143 builder.append(' '); 144 builder.append(instructionSet); 145 return mInstaller.execute(builder.toString()); 146 } 147 148 public int rmdex(String codePath, String instructionSet) { 149 if (!isValidInstructionSet(instructionSet)) { 150 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 151 return -1; 152 } 153 154 StringBuilder builder = new StringBuilder("rmdex"); 155 builder.append(' '); 156 builder.append(codePath); 157 builder.append(' '); 158 builder.append(instructionSet); 159 return mInstaller.execute(builder.toString()); 160 } 161 162 /** 163 * Removes packageDir or its subdirectory 164 */ 165 public int rmPackageDir(String packageDir) { 166 StringBuilder builder = new StringBuilder("rmpackagedir"); 167 builder.append(' '); 168 builder.append(packageDir); 169 return mInstaller.execute(builder.toString()); 170 } 171 172 @Deprecated 173 public int remove(String name, int userId) { 174 return remove(null, name, userId); 175 } 176 177 public int remove(String uuid, String name, int userId) { 178 StringBuilder builder = new StringBuilder("remove"); 179 builder.append(' '); 180 builder.append(escapeNull(uuid)); 181 builder.append(' '); 182 builder.append(name); 183 builder.append(' '); 184 builder.append(userId); 185 return mInstaller.execute(builder.toString()); 186 } 187 188 public int rename(String oldname, String newname) { 189 StringBuilder builder = new StringBuilder("rename"); 190 builder.append(' '); 191 builder.append(oldname); 192 builder.append(' '); 193 builder.append(newname); 194 return mInstaller.execute(builder.toString()); 195 } 196 197 @Deprecated 198 public int fixUid(String name, int uid, int gid) { 199 return fixUid(null, name, uid, gid); 200 } 201 202 public int fixUid(String uuid, String name, int uid, int gid) { 203 StringBuilder builder = new StringBuilder("fixuid"); 204 builder.append(' '); 205 builder.append(escapeNull(uuid)); 206 builder.append(' '); 207 builder.append(name); 208 builder.append(' '); 209 builder.append(uid); 210 builder.append(' '); 211 builder.append(gid); 212 return mInstaller.execute(builder.toString()); 213 } 214 215 @Deprecated 216 public int deleteCacheFiles(String name, int userId) { 217 return deleteCacheFiles(null, name, userId); 218 } 219 220 public int deleteCacheFiles(String uuid, String name, int userId) { 221 StringBuilder builder = new StringBuilder("rmcache"); 222 builder.append(' '); 223 builder.append(escapeNull(uuid)); 224 builder.append(' '); 225 builder.append(name); 226 builder.append(' '); 227 builder.append(userId); 228 return mInstaller.execute(builder.toString()); 229 } 230 231 @Deprecated 232 public int deleteCodeCacheFiles(String name, int userId) { 233 return deleteCodeCacheFiles(null, name, userId); 234 } 235 236 public int deleteCodeCacheFiles(String uuid, String name, int userId) { 237 StringBuilder builder = new StringBuilder("rmcodecache"); 238 builder.append(' '); 239 builder.append(escapeNull(uuid)); 240 builder.append(' '); 241 builder.append(name); 242 builder.append(' '); 243 builder.append(userId); 244 return mInstaller.execute(builder.toString()); 245 } 246 247 @Deprecated 248 public int createUserData(String name, int uid, int userId, String seinfo) { 249 return createUserData(null, name, uid, userId, seinfo); 250 } 251 252 public int createUserData(String uuid, String name, int uid, int userId, String seinfo) { 253 StringBuilder builder = new StringBuilder("mkuserdata"); 254 builder.append(' '); 255 builder.append(escapeNull(uuid)); 256 builder.append(' '); 257 builder.append(name); 258 builder.append(' '); 259 builder.append(uid); 260 builder.append(' '); 261 builder.append(userId); 262 builder.append(' '); 263 builder.append(seinfo != null ? seinfo : "!"); 264 return mInstaller.execute(builder.toString()); 265 } 266 267 public int createUserConfig(int userId) { 268 StringBuilder builder = new StringBuilder("mkuserconfig"); 269 builder.append(' '); 270 builder.append(userId); 271 return mInstaller.execute(builder.toString()); 272 } 273 274 @Deprecated 275 public int removeUserDataDirs(int userId) { 276 return removeUserDataDirs(null, userId); 277 } 278 279 public int removeUserDataDirs(String uuid, int userId) { 280 StringBuilder builder = new StringBuilder("rmuser"); 281 builder.append(' '); 282 builder.append(escapeNull(uuid)); 283 builder.append(' '); 284 builder.append(userId); 285 return mInstaller.execute(builder.toString()); 286 } 287 288 public int copyCompleteApp(String fromUuid, String toUuid, String packageName, 289 String dataAppName, int appId, String seinfo) { 290 StringBuilder builder = new StringBuilder("cpcompleteapp"); 291 builder.append(' '); 292 builder.append(escapeNull(fromUuid)); 293 builder.append(' '); 294 builder.append(escapeNull(toUuid)); 295 builder.append(' '); 296 builder.append(packageName); 297 builder.append(' '); 298 builder.append(dataAppName); 299 builder.append(' '); 300 builder.append(appId); 301 builder.append(' '); 302 builder.append(seinfo); 303 return mInstaller.execute(builder.toString()); 304 } 305 306 @Deprecated 307 public int clearUserData(String name, int userId) { 308 return clearUserData(null, name, userId); 309 } 310 311 public int clearUserData(String uuid, String name, int userId) { 312 StringBuilder builder = new StringBuilder("rmuserdata"); 313 builder.append(' '); 314 builder.append(escapeNull(uuid)); 315 builder.append(' '); 316 builder.append(name); 317 builder.append(' '); 318 builder.append(userId); 319 return mInstaller.execute(builder.toString()); 320 } 321 322 public int markBootComplete(String instructionSet) { 323 if (!isValidInstructionSet(instructionSet)) { 324 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 325 return -1; 326 } 327 328 StringBuilder builder = new StringBuilder("markbootcomplete"); 329 builder.append(' '); 330 builder.append(instructionSet); 331 return mInstaller.execute(builder.toString()); 332 } 333 334 @Deprecated 335 public int freeCache(long freeStorageSize) { 336 return freeCache(null, freeStorageSize); 337 } 338 339 public int freeCache(String uuid, long freeStorageSize) { 340 StringBuilder builder = new StringBuilder("freecache"); 341 builder.append(' '); 342 builder.append(escapeNull(uuid)); 343 builder.append(' '); 344 builder.append(String.valueOf(freeStorageSize)); 345 return mInstaller.execute(builder.toString()); 346 } 347 348 @Deprecated 349 public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, 350 String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) { 351 return getSizeInfo(null, pkgName, persona, apkPath, libDirPath, fwdLockApkPath, asecPath, 352 instructionSets, pStats); 353 } 354 355 public int getSizeInfo(String uuid, String pkgName, int persona, String apkPath, 356 String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets, 357 PackageStats pStats) { 358 for (String instructionSet : instructionSets) { 359 if (!isValidInstructionSet(instructionSet)) { 360 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 361 return -1; 362 } 363 } 364 365 StringBuilder builder = new StringBuilder("getsize"); 366 builder.append(' '); 367 builder.append(escapeNull(uuid)); 368 builder.append(' '); 369 builder.append(pkgName); 370 builder.append(' '); 371 builder.append(persona); 372 builder.append(' '); 373 builder.append(apkPath); 374 builder.append(' '); 375 // TODO: Extend getSizeInfo to look at the full subdirectory tree, 376 // not just the first level. 377 builder.append(libDirPath != null ? libDirPath : "!"); 378 builder.append(' '); 379 builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!"); 380 builder.append(' '); 381 builder.append(asecPath != null ? asecPath : "!"); 382 builder.append(' '); 383 // TODO: Extend getSizeInfo to look at *all* instrution sets, not 384 // just the primary. 385 builder.append(instructionSets[0]); 386 387 String s = mInstaller.transact(builder.toString()); 388 String res[] = s.split(" "); 389 390 if ((res == null) || (res.length != 5)) { 391 return -1; 392 } 393 try { 394 pStats.codeSize = Long.parseLong(res[1]); 395 pStats.dataSize = Long.parseLong(res[2]); 396 pStats.cacheSize = Long.parseLong(res[3]); 397 pStats.externalCodeSize = Long.parseLong(res[4]); 398 return Integer.parseInt(res[0]); 399 } catch (NumberFormatException e) { 400 return -1; 401 } 402 } 403 404 public int moveFiles() { 405 return mInstaller.execute("movefiles"); 406 } 407 408 @Deprecated 409 public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) { 410 return linkNativeLibraryDirectory(null, dataPath, nativeLibPath32, userId); 411 } 412 413 /** 414 * Links the 32 bit native library directory in an application's data directory to the 415 * real location for backward compatibility. Note that no such symlink is created for 416 * 64 bit shared libraries. 417 * 418 * @return -1 on error 419 */ 420 public int linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32, 421 int userId) { 422 if (dataPath == null) { 423 Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null"); 424 return -1; 425 } else if (nativeLibPath32 == null) { 426 Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null"); 427 return -1; 428 } 429 430 StringBuilder builder = new StringBuilder("linklib"); 431 builder.append(' '); 432 builder.append(escapeNull(uuid)); 433 builder.append(' '); 434 builder.append(dataPath); 435 builder.append(' '); 436 builder.append(nativeLibPath32); 437 builder.append(' '); 438 builder.append(userId); 439 440 return mInstaller.execute(builder.toString()); 441 } 442 443 @Deprecated 444 public boolean restoreconData(String pkgName, String seinfo, int uid) { 445 return restoreconData(null, pkgName, seinfo, uid); 446 } 447 448 public boolean restoreconData(String uuid, String pkgName, String seinfo, int uid) { 449 StringBuilder builder = new StringBuilder("restorecondata"); 450 builder.append(' '); 451 builder.append(escapeNull(uuid)); 452 builder.append(' '); 453 builder.append(pkgName); 454 builder.append(' '); 455 builder.append(seinfo != null ? seinfo : "!"); 456 builder.append(' '); 457 builder.append(uid); 458 return (mInstaller.execute(builder.toString()) == 0); 459 } 460 461 public int createOatDir(String oatDir, String dexInstructionSet) { 462 StringBuilder builder = new StringBuilder("createoatdir"); 463 builder.append(' '); 464 builder.append(oatDir); 465 builder.append(' '); 466 builder.append(dexInstructionSet); 467 return mInstaller.execute(builder.toString()); 468 } 469 470 471 public int linkFile(String relativePath, String fromBase, String toBase) { 472 StringBuilder builder = new StringBuilder("linkfile"); 473 builder.append(' '); 474 builder.append(relativePath); 475 builder.append(' '); 476 builder.append(fromBase); 477 builder.append(' '); 478 builder.append(toBase); 479 return mInstaller.execute(builder.toString()); 480 } 481 482 /** 483 * Returns true iff. {@code instructionSet} is a valid instruction set. 484 */ 485 private static boolean isValidInstructionSet(String instructionSet) { 486 if (instructionSet == null) { 487 return false; 488 } 489 490 for (String abi : Build.SUPPORTED_ABIS) { 491 if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) { 492 return true; 493 } 494 } 495 496 return false; 497 } 498} 499