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