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