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