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 33 public Installer(Context context) { 34 super(context); 35 mInstaller = new InstallerConnection(); 36 } 37 38 @Override 39 public void onStart() { 40 Slog.i(TAG, "Waiting for installd to be ready."); 41 ping(); 42 } 43 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 219 public int markBootComplete(String instructionSet) { 220 if (!isValidInstructionSet(instructionSet)) { 221 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 222 return -1; 223 } 224 225 StringBuilder builder = new StringBuilder("markbootcomplete"); 226 builder.append(' '); 227 builder.append(instructionSet); 228 return mInstaller.execute(builder.toString()); 229 } 230 231 public boolean ping() { 232 if (mInstaller.execute("ping") < 0) { 233 return false; 234 } else { 235 return true; 236 } 237 } 238 239 public int freeCache(long freeStorageSize) { 240 StringBuilder builder = new StringBuilder("freecache"); 241 builder.append(' '); 242 builder.append(String.valueOf(freeStorageSize)); 243 return mInstaller.execute(builder.toString()); 244 } 245 246 public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, 247 String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) { 248 for (String instructionSet : instructionSets) { 249 if (!isValidInstructionSet(instructionSet)) { 250 Slog.e(TAG, "Invalid instruction set: " + instructionSet); 251 return -1; 252 } 253 } 254 255 StringBuilder builder = new StringBuilder("getsize"); 256 builder.append(' '); 257 builder.append(pkgName); 258 builder.append(' '); 259 builder.append(persona); 260 builder.append(' '); 261 builder.append(apkPath); 262 builder.append(' '); 263 // TODO: Extend getSizeInfo to look at the full subdirectory tree, 264 // not just the first level. 265 builder.append(libDirPath != null ? libDirPath : "!"); 266 builder.append(' '); 267 builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!"); 268 builder.append(' '); 269 builder.append(asecPath != null ? asecPath : "!"); 270 builder.append(' '); 271 // TODO: Extend getSizeInfo to look at *all* instrution sets, not 272 // just the primary. 273 builder.append(instructionSets[0]); 274 275 String s = mInstaller.transact(builder.toString()); 276 String res[] = s.split(" "); 277 278 if ((res == null) || (res.length != 5)) { 279 return -1; 280 } 281 try { 282 pStats.codeSize = Long.parseLong(res[1]); 283 pStats.dataSize = Long.parseLong(res[2]); 284 pStats.cacheSize = Long.parseLong(res[3]); 285 pStats.externalCodeSize = Long.parseLong(res[4]); 286 return Integer.parseInt(res[0]); 287 } catch (NumberFormatException e) { 288 return -1; 289 } 290 } 291 292 public int moveFiles() { 293 return mInstaller.execute("movefiles"); 294 } 295 296 /** 297 * Links the 32 bit native library directory in an application's data directory to the 298 * real location for backward compatibility. Note that no such symlink is created for 299 * 64 bit shared libraries. 300 * 301 * @return -1 on error 302 */ 303 public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) { 304 if (dataPath == null) { 305 Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null"); 306 return -1; 307 } else if (nativeLibPath32 == null) { 308 Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null"); 309 return -1; 310 } 311 312 StringBuilder builder = new StringBuilder("linklib "); 313 builder.append(dataPath); 314 builder.append(' '); 315 builder.append(nativeLibPath32); 316 builder.append(' '); 317 builder.append(userId); 318 319 return mInstaller.execute(builder.toString()); 320 } 321 322 public boolean restoreconData(String pkgName, String seinfo, int uid) { 323 StringBuilder builder = new StringBuilder("restorecondata"); 324 builder.append(' '); 325 builder.append(pkgName); 326 builder.append(' '); 327 builder.append(seinfo != null ? seinfo : "!"); 328 builder.append(' '); 329 builder.append(uid); 330 return (mInstaller.execute(builder.toString()) == 0); 331 } 332 333 /** 334 * Returns true iff. {@code instructionSet} is a valid instruction set. 335 */ 336 private static boolean isValidInstructionSet(String instructionSet) { 337 if (instructionSet == null) { 338 return false; 339 } 340 341 for (String abi : Build.SUPPORTED_ABIS) { 342 if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) { 343 return true; 344 } 345 } 346 347 return false; 348 } 349 } 350