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