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