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; 18 19import android.content.pm.PackageStats; 20import android.net.LocalSocketAddress; 21import android.net.LocalSocket; 22import android.util.Config; 23import android.util.Log; 24 25import java.io.IOException; 26import java.io.InputStream; 27import java.io.OutputStream; 28import java.net.Socket; 29 30 31class Installer { 32 private static final String TAG = "Installer"; 33 InputStream mIn; 34 OutputStream mOut; 35 LocalSocket mSocket; 36 37 byte buf[] = new byte[1024]; 38 int buflen = 0; 39 40 private boolean connect() { 41 if (mSocket != null) { 42 return true; 43 } 44 Log.i(TAG, "connecting..."); 45 try { 46 mSocket = new LocalSocket(); 47 48 LocalSocketAddress address = new LocalSocketAddress( 49 "installd", LocalSocketAddress.Namespace.RESERVED); 50 51 mSocket.connect(address); 52 53 mIn = mSocket.getInputStream(); 54 mOut = mSocket.getOutputStream(); 55 } catch (IOException ex) { 56 disconnect(); 57 return false; 58 } 59 return true; 60 } 61 62 private void disconnect() { 63 Log.i(TAG,"disconnecting..."); 64 try { 65 if (mSocket != null) mSocket.close(); 66 } catch (IOException ex) { } 67 try { 68 if (mIn != null) mIn.close(); 69 } catch (IOException ex) { } 70 try { 71 if (mOut != null) mOut.close(); 72 } catch (IOException ex) { } 73 mSocket = null; 74 mIn = null; 75 mOut = null; 76 } 77 78 private boolean readBytes(byte buffer[], int len) { 79 int off = 0, count; 80 if (len < 0) return false; 81 while (off != len) { 82 try { 83 count = mIn.read(buffer, off, len - off); 84 if (count <= 0) { 85 Log.e(TAG, "read error " + count); 86 break; 87 } 88 off += count; 89 } catch (IOException ex) { 90 Log.e(TAG,"read exception"); 91 break; 92 } 93 } 94// Log.i(TAG, "read "+len+" bytes"); 95 if (off == len) return true; 96 disconnect(); 97 return false; 98 } 99 100 private boolean readReply() { 101 int len; 102 buflen = 0; 103 if (!readBytes(buf, 2)) return false; 104 len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); 105 if ((len < 1) || (len > 1024)) { 106 Log.e(TAG,"invalid reply length ("+len+")"); 107 disconnect(); 108 return false; 109 } 110 if (!readBytes(buf, len)) return false; 111 buflen = len; 112 return true; 113 } 114 115 private boolean writeCommand(String _cmd) { 116 byte[] cmd = _cmd.getBytes(); 117 int len = cmd.length; 118 if ((len < 1) || (len > 1024)) return false; 119 buf[0] = (byte) (len & 0xff); 120 buf[1] = (byte) ((len >> 8) & 0xff); 121 try { 122 mOut.write(buf, 0, 2); 123 mOut.write(cmd, 0, len); 124 } catch (IOException ex) { 125 Log.e(TAG,"write error"); 126 disconnect(); 127 return false; 128 } 129 return true; 130 } 131 132 private synchronized String transaction(String cmd) { 133 if (!connect()) { 134 Log.e(TAG, "connection failed"); 135 return "-1"; 136 } 137 138 if (!writeCommand(cmd)) { 139 /* If installd died and restarted in the background 140 * (unlikely but possible) we'll fail on the next 141 * write (this one). Try to reconnect and write 142 * the command one more time before giving up. 143 */ 144 Log.e(TAG, "write command failed? reconnect!"); 145 if (!connect() || !writeCommand(cmd)) { 146 return "-1"; 147 } 148 } 149// Log.i(TAG,"send: '"+cmd+"'"); 150 if (readReply()) { 151 String s = new String(buf, 0, buflen); 152// Log.i(TAG,"recv: '"+s+"'"); 153 return s; 154 } else { 155// Log.i(TAG,"fail"); 156 return "-1"; 157 } 158 } 159 160 private int execute(String cmd) { 161 String res = transaction(cmd); 162 try { 163 return Integer.parseInt(res); 164 } catch (NumberFormatException ex) { 165 return -1; 166 } 167 } 168 169 public int install(String name, int uid, int gid) { 170 StringBuilder builder = new StringBuilder("install"); 171 builder.append(' '); 172 builder.append(name); 173 builder.append(' '); 174 builder.append(uid); 175 builder.append(' '); 176 builder.append(gid); 177 return execute(builder.toString()); 178 } 179 180 public int dexopt(String apkPath, int uid, boolean isPublic) { 181 StringBuilder builder = new StringBuilder("dexopt"); 182 builder.append(' '); 183 builder.append(apkPath); 184 builder.append(' '); 185 builder.append(uid); 186 builder.append(isPublic ? " 1" : " 0"); 187 return execute(builder.toString()); 188 } 189 190 public int movedex(String srcPath, String dstPath) { 191 StringBuilder builder = new StringBuilder("movedex"); 192 builder.append(' '); 193 builder.append(srcPath); 194 builder.append(' '); 195 builder.append(dstPath); 196 return execute(builder.toString()); 197 } 198 199 public int rmdex(String codePath) { 200 StringBuilder builder = new StringBuilder("rmdex"); 201 builder.append(' '); 202 builder.append(codePath); 203 return execute(builder.toString()); 204 } 205 206 public int remove(String name) { 207 StringBuilder builder = new StringBuilder("remove"); 208 builder.append(' '); 209 builder.append(name); 210 return execute(builder.toString()); 211 } 212 213 public int deleteCacheFiles(String name) { 214 StringBuilder builder = new StringBuilder("rmcache"); 215 builder.append(' '); 216 builder.append(name); 217 return execute(builder.toString()); 218 } 219 220 public int clearUserData(String name) { 221 StringBuilder builder = new StringBuilder("rmuserdata"); 222 builder.append(' '); 223 builder.append(name); 224 return execute(builder.toString()); 225 } 226 227 public boolean ping() { 228 if (execute("ping") < 0) { 229 return false; 230 } else { 231 return true; 232 } 233 } 234 235 public int freeCache(long freeStorageSize) { 236 StringBuilder builder = new StringBuilder("freecache"); 237 builder.append(' '); 238 builder.append(String.valueOf(freeStorageSize)); 239 return execute(builder.toString()); 240 } 241 242 public int setForwardLockPerm(String packageName, int gid) { 243 StringBuilder builder = new StringBuilder("protect"); 244 builder.append(' '); 245 builder.append(packageName); 246 builder.append(' '); 247 builder.append(gid); 248 return execute(builder.toString()); 249 } 250 251 public int getSizeInfo(String pkgName, String apkPath, 252 String fwdLockApkPath, PackageStats pStats) { 253 StringBuilder builder = new StringBuilder("getsize"); 254 builder.append(' '); 255 builder.append(pkgName); 256 builder.append(' '); 257 builder.append(apkPath); 258 builder.append(' '); 259 builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!"); 260 261 String s = transaction(builder.toString()); 262 String res[] = s.split(" "); 263 264 if((res == null) || (res.length != 4)) { 265 return -1; 266 } 267 try { 268 pStats.codeSize = Long.parseLong(res[1]); 269 pStats.dataSize = Long.parseLong(res[2]); 270 pStats.cacheSize = Long.parseLong(res[3]); 271 return Integer.parseInt(res[0]); 272 } catch (NumberFormatException e) { 273 return -1; 274 } 275 } 276} 277