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.content.Context; 20 import android.content.pm.PackageStats; 21 import android.os.Build; 22 import android.util.Slog; 23 import dalvik.system.VMRuntime; 24 25 import com.android.internal.os.InstallerConnection; 26 import com.android.server.SystemService; 27 28 public final class Installer extends SystemService { 29 private static final String TAG = "Installer"; 30 31 private final InstallerConnection mInstaller; 32 Installer(Context context)33 public Installer(Context context) { 34 super(context); 35 mInstaller = new InstallerConnection(); 36 } 37 38 @Override onStart()39 public void onStart() { 40 Slog.i(TAG, "Waiting for installd to be ready."); 41 ping(); 42 } 43 install(String name, int uid, int gid, String seinfo)44 public int install(String name, int uid, int gid, String seinfo) { 45 StringBuilder builder = new StringBuilder("install"); 46 builder.append(' '); 47 builder.append(name); 48 builder.append(' '); 49 builder.append(uid); 50 builder.append(' '); 51 builder.append(gid); 52 builder.append(' '); 53 builder.append(seinfo != null ? seinfo : "!"); 54 return mInstaller.execute(builder.toString()); 55 } 56 patchoat(String apkPath, int uid, boolean isPublic, String pkgName, String instructionSet)57 public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName, 58 String instructionSet) { 59 if (!isValidInstructionSet(instructionSet)) { 60 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 61 return -1; 62 } 63 64 return mInstaller.patchoat(apkPath, uid, isPublic, pkgName, instructionSet); 65 } 66 patchoat(String apkPath, int uid, boolean isPublic, String instructionSet)67 public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) { 68 if (!isValidInstructionSet(instructionSet)) { 69 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 70 return -1; 71 } 72 73 return mInstaller.patchoat(apkPath, uid, isPublic, instructionSet); 74 } 75 dexopt(String apkPath, int uid, boolean isPublic, String instructionSet)76 public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) { 77 if (!isValidInstructionSet(instructionSet)) { 78 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 79 return -1; 80 } 81 82 return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet); 83 } 84 dexopt(String apkPath, int uid, boolean isPublic, String pkgName, String instructionSet, boolean vmSafeMode)85 public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, 86 String instructionSet, boolean vmSafeMode) { 87 if (!isValidInstructionSet(instructionSet)) { 88 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 89 return -1; 90 } 91 92 return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, instructionSet, vmSafeMode); 93 } 94 idmap(String targetApkPath, String overlayApkPath, int uid)95 public int idmap(String targetApkPath, String overlayApkPath, int uid) { 96 StringBuilder builder = new StringBuilder("idmap"); 97 builder.append(' '); 98 builder.append(targetApkPath); 99 builder.append(' '); 100 builder.append(overlayApkPath); 101 builder.append(' '); 102 builder.append(uid); 103 return mInstaller.execute(builder.toString()); 104 } 105 movedex(String srcPath, String dstPath, String instructionSet)106 public int movedex(String srcPath, String dstPath, String instructionSet) { 107 if (!isValidInstructionSet(instructionSet)) { 108 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 109 return -1; 110 } 111 112 StringBuilder builder = new StringBuilder("movedex"); 113 builder.append(' '); 114 builder.append(srcPath); 115 builder.append(' '); 116 builder.append(dstPath); 117 builder.append(' '); 118 builder.append(instructionSet); 119 return mInstaller.execute(builder.toString()); 120 } 121 rmdex(String codePath, String instructionSet)122 public int rmdex(String codePath, String instructionSet) { 123 if (!isValidInstructionSet(instructionSet)) { 124 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 125 return -1; 126 } 127 128 StringBuilder builder = new StringBuilder("rmdex"); 129 builder.append(' '); 130 builder.append(codePath); 131 builder.append(' '); 132 builder.append(instructionSet); 133 return mInstaller.execute(builder.toString()); 134 } 135 remove(String name, int userId)136 public int remove(String name, int userId) { 137 StringBuilder builder = new StringBuilder("remove"); 138 builder.append(' '); 139 builder.append(name); 140 builder.append(' '); 141 builder.append(userId); 142 return mInstaller.execute(builder.toString()); 143 } 144 rename(String oldname, String newname)145 public int rename(String oldname, String newname) { 146 StringBuilder builder = new StringBuilder("rename"); 147 builder.append(' '); 148 builder.append(oldname); 149 builder.append(' '); 150 builder.append(newname); 151 return mInstaller.execute(builder.toString()); 152 } 153 fixUid(String name, int uid, int gid)154 public int fixUid(String name, int uid, int gid) { 155 StringBuilder builder = new StringBuilder("fixuid"); 156 builder.append(' '); 157 builder.append(name); 158 builder.append(' '); 159 builder.append(uid); 160 builder.append(' '); 161 builder.append(gid); 162 return mInstaller.execute(builder.toString()); 163 } 164 deleteCacheFiles(String name, int userId)165 public int deleteCacheFiles(String name, int userId) { 166 StringBuilder builder = new StringBuilder("rmcache"); 167 builder.append(' '); 168 builder.append(name); 169 builder.append(' '); 170 builder.append(userId); 171 return mInstaller.execute(builder.toString()); 172 } 173 deleteCodeCacheFiles(String name, int userId)174 public int deleteCodeCacheFiles(String name, int userId) { 175 StringBuilder builder = new StringBuilder("rmcodecache"); 176 builder.append(' '); 177 builder.append(name); 178 builder.append(' '); 179 builder.append(userId); 180 return mInstaller.execute(builder.toString()); 181 } 182 createUserData(String name, int uid, int userId, String seinfo)183 public int createUserData(String name, int uid, int userId, String seinfo) { 184 StringBuilder builder = new StringBuilder("mkuserdata"); 185 builder.append(' '); 186 builder.append(name); 187 builder.append(' '); 188 builder.append(uid); 189 builder.append(' '); 190 builder.append(userId); 191 builder.append(' '); 192 builder.append(seinfo != null ? seinfo : "!"); 193 return mInstaller.execute(builder.toString()); 194 } 195 createUserConfig(int userId)196 public int createUserConfig(int userId) { 197 StringBuilder builder = new StringBuilder("mkuserconfig"); 198 builder.append(' '); 199 builder.append(userId); 200 return mInstaller.execute(builder.toString()); 201 } 202 removeUserDataDirs(int userId)203 public int removeUserDataDirs(int userId) { 204 StringBuilder builder = new StringBuilder("rmuser"); 205 builder.append(' '); 206 builder.append(userId); 207 return mInstaller.execute(builder.toString()); 208 } 209 clearUserData(String name, int userId)210 public int clearUserData(String name, int userId) { 211 StringBuilder builder = new StringBuilder("rmuserdata"); 212 builder.append(' '); 213 builder.append(name); 214 builder.append(' '); 215 builder.append(userId); 216 return mInstaller.execute(builder.toString()); 217 } 218 ping()219 public boolean ping() { 220 if (mInstaller.execute("ping") < 0) { 221 return false; 222 } else { 223 return true; 224 } 225 } 226 freeCache(long freeStorageSize)227 public int freeCache(long freeStorageSize) { 228 StringBuilder builder = new StringBuilder("freecache"); 229 builder.append(' '); 230 builder.append(String.valueOf(freeStorageSize)); 231 return mInstaller.execute(builder.toString()); 232 } 233 getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats)234 public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, 235 String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) { 236 for (String instructionSet : instructionSets) { 237 if (!isValidInstructionSet(instructionSet)) { 238 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 239 return -1; 240 } 241 } 242 243 StringBuilder builder = new StringBuilder("getsize"); 244 builder.append(' '); 245 builder.append(pkgName); 246 builder.append(' '); 247 builder.append(persona); 248 builder.append(' '); 249 builder.append(apkPath); 250 builder.append(' '); 251 // TODO: Extend getSizeInfo to look at the full subdirectory tree, 252 // not just the first level. 253 builder.append(libDirPath != null ? libDirPath : "!"); 254 builder.append(' '); 255 builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!"); 256 builder.append(' '); 257 builder.append(asecPath != null ? asecPath : "!"); 258 builder.append(' '); 259 // TODO: Extend getSizeInfo to look at *all* instrution sets, not 260 // just the primary. 261 builder.append(instructionSets[0]); 262 263 String s = mInstaller.transact(builder.toString()); 264 String res[] = s.split(" "); 265 266 if ((res == null) || (res.length != 5)) { 267 return -1; 268 } 269 try { 270 pStats.codeSize = Long.parseLong(res[1]); 271 pStats.dataSize = Long.parseLong(res[2]); 272 pStats.cacheSize = Long.parseLong(res[3]); 273 pStats.externalCodeSize = Long.parseLong(res[4]); 274 return Integer.parseInt(res[0]); 275 } catch (NumberFormatException e) { 276 return -1; 277 } 278 } 279 moveFiles()280 public int moveFiles() { 281 return mInstaller.execute("movefiles"); 282 } 283 284 /** 285 * Links the 32 bit native library directory in an application's data directory to the 286 * real location for backward compatibility. Note that no such symlink is created for 287 * 64 bit shared libraries. 288 * 289 * @return -1 on error 290 */ linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId)291 public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) { 292 if (dataPath == null) { 293 Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null"); 294 return -1; 295 } else if (nativeLibPath32 == null) { 296 Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null"); 297 return -1; 298 } 299 300 StringBuilder builder = new StringBuilder("linklib "); 301 builder.append(dataPath); 302 builder.append(' '); 303 builder.append(nativeLibPath32); 304 builder.append(' '); 305 builder.append(userId); 306 307 return mInstaller.execute(builder.toString()); 308 } 309 restoreconData(String pkgName, String seinfo, int uid)310 public boolean restoreconData(String pkgName, String seinfo, int uid) { 311 StringBuilder builder = new StringBuilder("restorecondata"); 312 builder.append(' '); 313 builder.append(pkgName); 314 builder.append(' '); 315 builder.append(seinfo != null ? seinfo : "!"); 316 builder.append(' '); 317 builder.append(uid); 318 return (mInstaller.execute(builder.toString()) == 0); 319 } 320 321 /** 322 * Returns true iff. {@code instructionSet} is a valid instruction set. 323 */ isValidInstructionSet(String instructionSet)324 private static boolean isValidInstructionSet(String instructionSet) { 325 if (instructionSet == null) { 326 return false; 327 } 328 329 for (String abi : Build.SUPPORTED_ABIS) { 330 if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) { 331 return true; 332 } 333 } 334 335 return false; 336 } 337 } 338