Installer.java revision 324aa693b82656809b97e307676adbbce37c3d95
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) { 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 return execute(builder.toString()); 223 } 224 225 public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName) { 226 StringBuilder builder = new StringBuilder("dexopt"); 227 builder.append(' '); 228 builder.append(apkPath); 229 builder.append(' '); 230 builder.append(uid); 231 builder.append(isPublic ? " 1" : " 0"); 232 builder.append(' '); 233 builder.append(pkgName); 234 return execute(builder.toString()); 235 } 236 237 public int idmap(String targetApkPath, String overlayApkPath, int uid) { 238 StringBuilder builder = new StringBuilder("idmap"); 239 builder.append(' '); 240 builder.append(targetApkPath); 241 builder.append(' '); 242 builder.append(overlayApkPath); 243 builder.append(' '); 244 builder.append(uid); 245 return execute(builder.toString()); 246 } 247 248 public int movedex(String srcPath, String dstPath) { 249 StringBuilder builder = new StringBuilder("movedex"); 250 builder.append(' '); 251 builder.append(srcPath); 252 builder.append(' '); 253 builder.append(dstPath); 254 return execute(builder.toString()); 255 } 256 257 public int rmdex(String codePath) { 258 StringBuilder builder = new StringBuilder("rmdex"); 259 builder.append(' '); 260 builder.append(codePath); 261 return execute(builder.toString()); 262 } 263 264 public int remove(String name, int userId) { 265 StringBuilder builder = new StringBuilder("remove"); 266 builder.append(' '); 267 builder.append(name); 268 builder.append(' '); 269 builder.append(userId); 270 return execute(builder.toString()); 271 } 272 273 public int rename(String oldname, String newname) { 274 StringBuilder builder = new StringBuilder("rename"); 275 builder.append(' '); 276 builder.append(oldname); 277 builder.append(' '); 278 builder.append(newname); 279 return execute(builder.toString()); 280 } 281 282 public int fixUid(String name, int uid, int gid) { 283 StringBuilder builder = new StringBuilder("fixuid"); 284 builder.append(' '); 285 builder.append(name); 286 builder.append(' '); 287 builder.append(uid); 288 builder.append(' '); 289 builder.append(gid); 290 return execute(builder.toString()); 291 } 292 293 public int deleteCacheFiles(String name, int userId) { 294 StringBuilder builder = new StringBuilder("rmcache"); 295 builder.append(' '); 296 builder.append(name); 297 builder.append(' '); 298 builder.append(userId); 299 return execute(builder.toString()); 300 } 301 302 public int createUserData(String name, int uid, int userId, String seinfo) { 303 StringBuilder builder = new StringBuilder("mkuserdata"); 304 builder.append(' '); 305 builder.append(name); 306 builder.append(' '); 307 builder.append(uid); 308 builder.append(' '); 309 builder.append(userId); 310 builder.append(' '); 311 builder.append(seinfo != null ? seinfo : "!"); 312 return execute(builder.toString()); 313 } 314 315 public int removeUserDataDirs(int userId) { 316 StringBuilder builder = new StringBuilder("rmuser"); 317 builder.append(' '); 318 builder.append(userId); 319 return execute(builder.toString()); 320 } 321 322 public int clearUserData(String name, int userId) { 323 StringBuilder builder = new StringBuilder("rmuserdata"); 324 builder.append(' '); 325 builder.append(name); 326 builder.append(' '); 327 builder.append(userId); 328 return execute(builder.toString()); 329 } 330 331 public boolean ping() { 332 if (execute("ping") < 0) { 333 return false; 334 } else { 335 return true; 336 } 337 } 338 339 public int freeCache(long freeStorageSize) { 340 StringBuilder builder = new StringBuilder("freecache"); 341 builder.append(' '); 342 builder.append(String.valueOf(freeStorageSize)); 343 return execute(builder.toString()); 344 } 345 346 public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, 347 String fwdLockApkPath, String asecPath, PackageStats pStats) { 348 StringBuilder builder = new StringBuilder("getsize"); 349 builder.append(' '); 350 builder.append(pkgName); 351 builder.append(' '); 352 builder.append(persona); 353 builder.append(' '); 354 builder.append(apkPath); 355 builder.append(' '); 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 362 String s = transaction(builder.toString()); 363 String res[] = s.split(" "); 364 365 if ((res == null) || (res.length != 5)) { 366 return -1; 367 } 368 try { 369 pStats.codeSize = Long.parseLong(res[1]); 370 pStats.dataSize = Long.parseLong(res[2]); 371 pStats.cacheSize = Long.parseLong(res[3]); 372 pStats.externalCodeSize = Long.parseLong(res[4]); 373 return Integer.parseInt(res[0]); 374 } catch (NumberFormatException e) { 375 return -1; 376 } 377 } 378 379 public int moveFiles() { 380 return execute("movefiles"); 381 } 382 383 /** 384 * Links the native library directory in an application's directory to its 385 * real location. 386 * 387 * @param dataPath data directory where the application is 388 * @param nativeLibPath target native library path 389 * @return -1 on error 390 */ 391 public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath, int userId) { 392 if (dataPath == null) { 393 Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null"); 394 return -1; 395 } else if (nativeLibPath == null) { 396 Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null"); 397 return -1; 398 } 399 400 StringBuilder builder = new StringBuilder("linklib "); 401 builder.append(dataPath); 402 builder.append(' '); 403 builder.append(nativeLibPath); 404 builder.append(' '); 405 builder.append(userId); 406 407 return execute(builder.toString()); 408 } 409} 410