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 17 package com.android.server.pm; 18 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.content.pm.PackageStats; 22 import android.os.Build; 23 import android.text.TextUtils; 24 import android.util.Slog; 25 26 import dalvik.system.VMRuntime; 27 28 import com.android.internal.os.InstallerConnection; 29 import com.android.server.SystemService; 30 31 public final class Installer extends SystemService { 32 private static final String TAG = "Installer"; 33 34 private final InstallerConnection mInstaller; 35 Installer(Context context)36 public Installer(Context context) { 37 super(context); 38 mInstaller = new InstallerConnection(); 39 } 40 41 @Override onStart()42 public void onStart() { 43 Slog.i(TAG, "Waiting for installd to be ready."); 44 mInstaller.waitForConnection(); 45 } 46 escapeNull(String arg)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 install(String name, int uid, int gid, String seinfo)59 public int install(String name, int uid, int gid, String seinfo) { 60 return install(null, name, uid, gid, seinfo); 61 } 62 install(String uuid, String name, int uid, int gid, String seinfo)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 dexopt(String apkPath, int uid, boolean isPublic, String instructionSet, int dexoptNeeded)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 dexopt(String apkPath, int uid, boolean isPublic, String pkgName, String instructionSet, int dexoptNeeded, boolean vmSafeMode, boolean debuggable, @Nullable String outputPath)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 idmap(String targetApkPath, String overlayApkPath, int uid)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 movedex(String srcPath, String dstPath, String instructionSet)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 rmdex(String codePath, String instructionSet)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 */ rmPackageDir(String packageDir)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 remove(String name, int userId)152 public int remove(String name, int userId) { 153 return remove(null, name, userId); 154 } 155 remove(String uuid, String name, int userId)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 rename(String oldname, String newname)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 fixUid(String name, int uid, int gid)177 public int fixUid(String name, int uid, int gid) { 178 return fixUid(null, name, uid, gid); 179 } 180 fixUid(String uuid, String name, int uid, int gid)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 deleteCacheFiles(String name, int userId)195 public int deleteCacheFiles(String name, int userId) { 196 return deleteCacheFiles(null, name, userId); 197 } 198 deleteCacheFiles(String uuid, String name, int userId)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 deleteCodeCacheFiles(String name, int userId)211 public int deleteCodeCacheFiles(String name, int userId) { 212 return deleteCodeCacheFiles(null, name, userId); 213 } 214 deleteCodeCacheFiles(String uuid, String name, int userId)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 createUserData(String name, int uid, int userId, String seinfo)227 public int createUserData(String name, int uid, int userId, String seinfo) { 228 return createUserData(null, name, uid, userId, seinfo); 229 } 230 createUserData(String uuid, String name, int uid, int userId, String seinfo)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 createUserConfig(int userId)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 removeUserDataDirs(int userId)254 public int removeUserDataDirs(int userId) { 255 return removeUserDataDirs(null, userId); 256 } 257 removeUserDataDirs(String uuid, int userId)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 copyCompleteApp(String fromUuid, String toUuid, String packageName, String dataAppName, int appId, String seinfo)267 public int copyCompleteApp(String fromUuid, String toUuid, String packageName, 268 String dataAppName, int appId, String seinfo) { 269 StringBuilder builder = new StringBuilder("cpcompleteapp"); 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 clearUserData(String name, int userId)286 public int clearUserData(String name, int userId) { 287 return clearUserData(null, name, userId); 288 } 289 clearUserData(String uuid, String name, int userId)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 markBootComplete(String instructionSet)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 @Deprecated freeCache(long freeStorageSize)314 public int freeCache(long freeStorageSize) { 315 return freeCache(null, freeStorageSize); 316 } 317 freeCache(String uuid, long freeStorageSize)318 public int freeCache(String uuid, long freeStorageSize) { 319 StringBuilder builder = new StringBuilder("freecache"); 320 builder.append(' '); 321 builder.append(escapeNull(uuid)); 322 builder.append(' '); 323 builder.append(String.valueOf(freeStorageSize)); 324 return mInstaller.execute(builder.toString()); 325 } 326 327 @Deprecated getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats)328 public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, 329 String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) { 330 return getSizeInfo(null, pkgName, persona, apkPath, libDirPath, fwdLockApkPath, asecPath, 331 instructionSets, pStats); 332 } 333 getSizeInfo(String uuid, String pkgName, int persona, String apkPath, String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats)334 public int getSizeInfo(String uuid, String pkgName, int persona, String apkPath, 335 String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets, 336 PackageStats pStats) { 337 for (String instructionSet : instructionSets) { 338 if (!isValidInstructionSet(instructionSet)) { 339 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 340 return -1; 341 } 342 } 343 344 StringBuilder builder = new StringBuilder("getsize"); 345 builder.append(' '); 346 builder.append(escapeNull(uuid)); 347 builder.append(' '); 348 builder.append(pkgName); 349 builder.append(' '); 350 builder.append(persona); 351 builder.append(' '); 352 builder.append(apkPath); 353 builder.append(' '); 354 // TODO: Extend getSizeInfo to look at the full subdirectory tree, 355 // not just the first level. 356 builder.append(libDirPath != null ? libDirPath : "!"); 357 builder.append(' '); 358 builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!"); 359 builder.append(' '); 360 builder.append(asecPath != null ? asecPath : "!"); 361 builder.append(' '); 362 // TODO: Extend getSizeInfo to look at *all* instrution sets, not 363 // just the primary. 364 builder.append(instructionSets[0]); 365 366 String s = mInstaller.transact(builder.toString()); 367 String res[] = s.split(" "); 368 369 if ((res == null) || (res.length != 5)) { 370 return -1; 371 } 372 try { 373 pStats.codeSize = Long.parseLong(res[1]); 374 pStats.dataSize = Long.parseLong(res[2]); 375 pStats.cacheSize = Long.parseLong(res[3]); 376 pStats.externalCodeSize = Long.parseLong(res[4]); 377 return Integer.parseInt(res[0]); 378 } catch (NumberFormatException e) { 379 return -1; 380 } 381 } 382 moveFiles()383 public int moveFiles() { 384 return mInstaller.execute("movefiles"); 385 } 386 387 @Deprecated linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId)388 public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) { 389 return linkNativeLibraryDirectory(null, dataPath, nativeLibPath32, userId); 390 } 391 392 /** 393 * Links the 32 bit native library directory in an application's data directory to the 394 * real location for backward compatibility. Note that no such symlink is created for 395 * 64 bit shared libraries. 396 * 397 * @return -1 on error 398 */ linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32, int userId)399 public int linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32, 400 int userId) { 401 if (dataPath == null) { 402 Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null"); 403 return -1; 404 } else if (nativeLibPath32 == null) { 405 Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null"); 406 return -1; 407 } 408 409 StringBuilder builder = new StringBuilder("linklib"); 410 builder.append(' '); 411 builder.append(escapeNull(uuid)); 412 builder.append(' '); 413 builder.append(dataPath); 414 builder.append(' '); 415 builder.append(nativeLibPath32); 416 builder.append(' '); 417 builder.append(userId); 418 419 return mInstaller.execute(builder.toString()); 420 } 421 422 @Deprecated restoreconData(String pkgName, String seinfo, int uid)423 public boolean restoreconData(String pkgName, String seinfo, int uid) { 424 return restoreconData(null, pkgName, seinfo, uid); 425 } 426 restoreconData(String uuid, String pkgName, String seinfo, int uid)427 public boolean restoreconData(String uuid, String pkgName, String seinfo, int uid) { 428 StringBuilder builder = new StringBuilder("restorecondata"); 429 builder.append(' '); 430 builder.append(escapeNull(uuid)); 431 builder.append(' '); 432 builder.append(pkgName); 433 builder.append(' '); 434 builder.append(seinfo != null ? seinfo : "!"); 435 builder.append(' '); 436 builder.append(uid); 437 return (mInstaller.execute(builder.toString()) == 0); 438 } 439 createOatDir(String oatDir, String dexInstructionSet)440 public int createOatDir(String oatDir, String dexInstructionSet) { 441 StringBuilder builder = new StringBuilder("createoatdir"); 442 builder.append(' '); 443 builder.append(oatDir); 444 builder.append(' '); 445 builder.append(dexInstructionSet); 446 return mInstaller.execute(builder.toString()); 447 } 448 449 linkFile(String relativePath, String fromBase, String toBase)450 public int linkFile(String relativePath, String fromBase, String toBase) { 451 StringBuilder builder = new StringBuilder("linkfile"); 452 builder.append(' '); 453 builder.append(relativePath); 454 builder.append(' '); 455 builder.append(fromBase); 456 builder.append(' '); 457 builder.append(toBase); 458 return mInstaller.execute(builder.toString()); 459 } 460 461 /** 462 * Returns true iff. {@code instructionSet} is a valid instruction set. 463 */ isValidInstructionSet(String instructionSet)464 private static boolean isValidInstructionSet(String instructionSet) { 465 if (instructionSet == null) { 466 return false; 467 } 468 469 for (String abi : Build.SUPPORTED_ABIS) { 470 if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) { 471 return true; 472 } 473 } 474 475 return false; 476 } 477 } 478