Installer.java revision 0f206a149d27385ef092a34e0009a8607d663659
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 com.android.server.SystemService; 20 21import android.content.Context; 22import android.content.pm.PackageStats; 23import android.net.LocalSocket; 24import android.net.LocalSocketAddress; 25import android.util.Slog; 26 27import java.io.IOException; 28import java.io.InputStream; 29import java.io.OutputStream; 30 31public final class Installer extends SystemService { 32 private static final String TAG = "Installer"; 33 34 private static final boolean LOCAL_DEBUG = false; 35 36 InputStream mIn; 37 OutputStream mOut; 38 LocalSocket mSocket; 39 40 byte buf[] = new byte[1024]; 41 int buflen = 0; 42 43 public Installer(Context context) { 44 super(context); 45 } 46 47 @Override 48 public void onStart() { 49 Slog.i(TAG, "Waiting for installd to be ready."); 50 ping(); 51 } 52 53 private boolean connect() { 54 if (mSocket != null) { 55 return true; 56 } 57 Slog.i(TAG, "connecting..."); 58 try { 59 mSocket = new LocalSocket(); 60 61 LocalSocketAddress address = new LocalSocketAddress("installd", 62 LocalSocketAddress.Namespace.RESERVED); 63 64 mSocket.connect(address); 65 66 mIn = mSocket.getInputStream(); 67 mOut = mSocket.getOutputStream(); 68 } catch (IOException ex) { 69 disconnect(); 70 return false; 71 } 72 return true; 73 } 74 75 private void disconnect() { 76 Slog.i(TAG, "disconnecting..."); 77 try { 78 if (mSocket != null) 79 mSocket.close(); 80 } catch (IOException ex) { 81 } 82 try { 83 if (mIn != null) 84 mIn.close(); 85 } catch (IOException ex) { 86 } 87 try { 88 if (mOut != null) 89 mOut.close(); 90 } catch (IOException ex) { 91 } 92 mSocket = null; 93 mIn = null; 94 mOut = null; 95 } 96 97 private boolean readBytes(byte buffer[], int len) { 98 int off = 0, count; 99 if (len < 0) 100 return false; 101 while (off != len) { 102 try { 103 count = mIn.read(buffer, off, len - off); 104 if (count <= 0) { 105 Slog.e(TAG, "read error " + count); 106 break; 107 } 108 off += count; 109 } catch (IOException ex) { 110 Slog.e(TAG, "read exception"); 111 break; 112 } 113 } 114 if (LOCAL_DEBUG) { 115 Slog.i(TAG, "read " + len + " bytes"); 116 } 117 if (off == len) 118 return true; 119 disconnect(); 120 return false; 121 } 122 123 private boolean readReply() { 124 int len; 125 buflen = 0; 126 if (!readBytes(buf, 2)) 127 return false; 128 len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); 129 if ((len < 1) || (len > 1024)) { 130 Slog.e(TAG, "invalid reply length (" + len + ")"); 131 disconnect(); 132 return false; 133 } 134 if (!readBytes(buf, len)) 135 return false; 136 buflen = len; 137 return true; 138 } 139 140 private boolean writeCommand(String _cmd) { 141 byte[] cmd = _cmd.getBytes(); 142 int len = cmd.length; 143 if ((len < 1) || (len > 1024)) 144 return false; 145 buf[0] = (byte) (len & 0xff); 146 buf[1] = (byte) ((len >> 8) & 0xff); 147 try { 148 mOut.write(buf, 0, 2); 149 mOut.write(cmd, 0, len); 150 } catch (IOException ex) { 151 Slog.e(TAG, "write error"); 152 disconnect(); 153 return false; 154 } 155 return true; 156 } 157 158 private synchronized String transaction(String cmd) { 159 if (!connect()) { 160 Slog.e(TAG, "connection failed"); 161 return "-1"; 162 } 163 164 if (!writeCommand(cmd)) { 165 /* 166 * If installd died and restarted in the background (unlikely but 167 * possible) we'll fail on the next write (this one). Try to 168 * reconnect and write the command one more time before giving up. 169 */ 170 Slog.e(TAG, "write command failed? reconnect!"); 171 if (!connect() || !writeCommand(cmd)) { 172 return "-1"; 173 } 174 } 175 if (LOCAL_DEBUG) { 176 Slog.i(TAG, "send: '" + cmd + "'"); 177 } 178 if (readReply()) { 179 String s = new String(buf, 0, buflen); 180 if (LOCAL_DEBUG) { 181 Slog.i(TAG, "recv: '" + s + "'"); 182 } 183 return s; 184 } else { 185 if (LOCAL_DEBUG) { 186 Slog.i(TAG, "fail"); 187 } 188 return "-1"; 189 } 190 } 191 192 private int execute(String cmd) { 193 String res = transaction(cmd); 194 try { 195 return Integer.parseInt(res); 196 } catch (NumberFormatException ex) { 197 return -1; 198 } 199 } 200 201 public int install(String name, int uid, int gid, String seinfo) { 202 StringBuilder builder = new StringBuilder("install"); 203 builder.append(' '); 204 builder.append(name); 205 builder.append(' '); 206 builder.append(uid); 207 builder.append(' '); 208 builder.append(gid); 209 builder.append(' '); 210 builder.append(seinfo != null ? seinfo : "!"); 211 return execute(builder.toString()); 212 } 213 214 public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) { 215 StringBuilder builder = new StringBuilder("dexopt"); 216 builder.append(' '); 217 builder.append(apkPath); 218 builder.append(' '); 219 builder.append(uid); 220 builder.append(isPublic ? " 1" : " 0"); 221 builder.append(" *"); // No pkgName arg present 222 builder.append(' '); 223 builder.append(instructionSet); 224 return execute(builder.toString()); 225 } 226 227 public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, 228 String instructionSet) { 229 StringBuilder builder = new StringBuilder("dexopt"); 230 builder.append(' '); 231 builder.append(apkPath); 232 builder.append(' '); 233 builder.append(uid); 234 builder.append(isPublic ? " 1" : " 0"); 235 builder.append(' '); 236 builder.append(pkgName); 237 builder.append(' '); 238 builder.append(instructionSet); 239 return execute(builder.toString()); 240 } 241 242 public int idmap(String targetApkPath, String overlayApkPath, int uid) { 243 StringBuilder builder = new StringBuilder("idmap"); 244 builder.append(' '); 245 builder.append(targetApkPath); 246 builder.append(' '); 247 builder.append(overlayApkPath); 248 builder.append(' '); 249 builder.append(uid); 250 return execute(builder.toString()); 251 } 252 253 public int movedex(String srcPath, String dstPath, String instructionSet) { 254 StringBuilder builder = new StringBuilder("movedex"); 255 builder.append(' '); 256 builder.append(srcPath); 257 builder.append(' '); 258 builder.append(dstPath); 259 builder.append(' '); 260 builder.append(instructionSet); 261 return execute(builder.toString()); 262 } 263 264 public int rmdex(String codePath, String instructionSet) { 265 StringBuilder builder = new StringBuilder("rmdex"); 266 builder.append(' '); 267 builder.append(codePath); 268 builder.append(' '); 269 builder.append(instructionSet); 270 return execute(builder.toString()); 271 } 272 273 public int remove(String name, int userId) { 274 StringBuilder builder = new StringBuilder("remove"); 275 builder.append(' '); 276 builder.append(name); 277 builder.append(' '); 278 builder.append(userId); 279 return execute(builder.toString()); 280 } 281 282 public int rename(String oldname, String newname) { 283 StringBuilder builder = new StringBuilder("rename"); 284 builder.append(' '); 285 builder.append(oldname); 286 builder.append(' '); 287 builder.append(newname); 288 return execute(builder.toString()); 289 } 290 291 public int fixUid(String name, int uid, int gid) { 292 StringBuilder builder = new StringBuilder("fixuid"); 293 builder.append(' '); 294 builder.append(name); 295 builder.append(' '); 296 builder.append(uid); 297 builder.append(' '); 298 builder.append(gid); 299 return execute(builder.toString()); 300 } 301 302 public int deleteCacheFiles(String name, int userId) { 303 StringBuilder builder = new StringBuilder("rmcache"); 304 builder.append(' '); 305 builder.append(name); 306 builder.append(' '); 307 builder.append(userId); 308 return execute(builder.toString()); 309 } 310 311 public int createUserData(String name, int uid, int userId, String seinfo) { 312 StringBuilder builder = new StringBuilder("mkuserdata"); 313 builder.append(' '); 314 builder.append(name); 315 builder.append(' '); 316 builder.append(uid); 317 builder.append(' '); 318 builder.append(userId); 319 builder.append(' '); 320 builder.append(seinfo != null ? seinfo : "!"); 321 return execute(builder.toString()); 322 } 323 324 public int removeUserDataDirs(int userId) { 325 StringBuilder builder = new StringBuilder("rmuser"); 326 builder.append(' '); 327 builder.append(userId); 328 return execute(builder.toString()); 329 } 330 331 public int clearUserData(String name, int userId) { 332 StringBuilder builder = new StringBuilder("rmuserdata"); 333 builder.append(' '); 334 builder.append(name); 335 builder.append(' '); 336 builder.append(userId); 337 return execute(builder.toString()); 338 } 339 340 public boolean ping() { 341 if (execute("ping") < 0) { 342 return false; 343 } else { 344 return true; 345 } 346 } 347 348 public int freeCache(long freeStorageSize) { 349 StringBuilder builder = new StringBuilder("freecache"); 350 builder.append(' '); 351 builder.append(String.valueOf(freeStorageSize)); 352 return execute(builder.toString()); 353 } 354 355 public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, 356 String fwdLockApkPath, String asecPath, String instructionSet, PackageStats pStats) { 357 StringBuilder builder = new StringBuilder("getsize"); 358 builder.append(' '); 359 builder.append(pkgName); 360 builder.append(' '); 361 builder.append(persona); 362 builder.append(' '); 363 builder.append(apkPath); 364 builder.append(' '); 365 builder.append(libDirPath != null ? libDirPath : "!"); 366 builder.append(' '); 367 builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!"); 368 builder.append(' '); 369 builder.append(asecPath != null ? asecPath : "!"); 370 builder.append(' '); 371 builder.append(instructionSet); 372 373 String s = transaction(builder.toString()); 374 String res[] = s.split(" "); 375 376 if ((res == null) || (res.length != 5)) { 377 return -1; 378 } 379 try { 380 pStats.codeSize = Long.parseLong(res[1]); 381 pStats.dataSize = Long.parseLong(res[2]); 382 pStats.cacheSize = Long.parseLong(res[3]); 383 pStats.externalCodeSize = Long.parseLong(res[4]); 384 return Integer.parseInt(res[0]); 385 } catch (NumberFormatException e) { 386 return -1; 387 } 388 } 389 390 public int moveFiles() { 391 return execute("movefiles"); 392 } 393 394 /** 395 * Links the native library directory in an application's directory to its 396 * real location. 397 * 398 * @param dataPath data directory where the application is 399 * @param nativeLibPath target native library path 400 * @return -1 on error 401 */ 402 public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath, int userId) { 403 if (dataPath == null) { 404 Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null"); 405 return -1; 406 } else if (nativeLibPath == null) { 407 Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null"); 408 return -1; 409 } 410 411 StringBuilder builder = new StringBuilder("linklib "); 412 builder.append(dataPath); 413 builder.append(' '); 414 builder.append(nativeLibPath); 415 builder.append(' '); 416 builder.append(userId); 417 418 return execute(builder.toString()); 419 } 420 421 public boolean restoreconData(String pkgName, String seinfo, int uid) { 422 StringBuilder builder = new StringBuilder("restorecondata"); 423 builder.append(' '); 424 builder.append(pkgName); 425 builder.append(' '); 426 builder.append(seinfo != null ? seinfo : "!"); 427 builder.append(' '); 428 builder.append(uid); 429 return (execute(builder.toString()) == 0); 430 } 431} 432