blob: 1f34eba59e9d6dacdffef019385246f346e0db14 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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;
Joe Onorato8a9b2202010-02-26 18:56:32 -080023import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
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 }
Joe Onorato8a9b2202010-02-26 18:56:32 -080044 Slog.i(TAG, "connecting...");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 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() {
Joe Onorato8a9b2202010-02-26 18:56:32 -080063 Slog.i(TAG,"disconnecting...");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 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) {
Joe Onorato8a9b2202010-02-26 18:56:32 -080085 Slog.e(TAG, "read error " + count);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 break;
87 }
88 off += count;
89 } catch (IOException ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -080090 Slog.e(TAG,"read exception");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 break;
92 }
93 }
Joe Onorato8a9b2202010-02-26 18:56:32 -080094// Slog.i(TAG, "read "+len+" bytes");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 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)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800106 Slog.e(TAG,"invalid reply length ("+len+")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 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) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800125 Slog.e(TAG,"write error");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 disconnect();
127 return false;
128 }
129 return true;
130 }
131
132 private synchronized String transaction(String cmd) {
133 if (!connect()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800134 Slog.e(TAG, "connection failed");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 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 */
Joe Onorato8a9b2202010-02-26 18:56:32 -0800144 Slog.e(TAG, "write command failed? reconnect!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 if (!connect() || !writeCommand(cmd)) {
146 return "-1";
147 }
148 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800149// Slog.i(TAG,"send: '"+cmd+"'");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 if (readReply()) {
151 String s = new String(buf, 0, buflen);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800152// Slog.i(TAG,"recv: '"+s+"'");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 return s;
154 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800155// Slog.i(TAG,"fail");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 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
Oscar Montemayora8529f62009-11-18 10:14:20 -0800169 public int install(String name, boolean useEncryptedFilesystem, int uid, int gid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 StringBuilder builder = new StringBuilder("install");
171 builder.append(' ');
172 builder.append(name);
173 builder.append(' ');
Oscar Montemayora8529f62009-11-18 10:14:20 -0800174 if (useEncryptedFilesystem) {
175 builder.append('1');
176 } else {
177 builder.append('0');
178 }
179 builder.append(' ');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 builder.append(uid);
181 builder.append(' ');
182 builder.append(gid);
183 return execute(builder.toString());
184 }
185
186 public int dexopt(String apkPath, int uid, boolean isPublic) {
187 StringBuilder builder = new StringBuilder("dexopt");
188 builder.append(' ');
189 builder.append(apkPath);
190 builder.append(' ');
191 builder.append(uid);
192 builder.append(isPublic ? " 1" : " 0");
193 return execute(builder.toString());
194 }
195
196 public int movedex(String srcPath, String dstPath) {
197 StringBuilder builder = new StringBuilder("movedex");
198 builder.append(' ');
199 builder.append(srcPath);
200 builder.append(' ');
201 builder.append(dstPath);
202 return execute(builder.toString());
203 }
204
205 public int rmdex(String codePath) {
206 StringBuilder builder = new StringBuilder("rmdex");
207 builder.append(' ');
208 builder.append(codePath);
209 return execute(builder.toString());
210 }
211
Oscar Montemayora8529f62009-11-18 10:14:20 -0800212 public int remove(String name, boolean useEncryptedFilesystem) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 StringBuilder builder = new StringBuilder("remove");
214 builder.append(' ');
215 builder.append(name);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800216 builder.append(' ');
217 if (useEncryptedFilesystem) {
218 builder.append('1');
219 } else {
220 builder.append('0');
221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 return execute(builder.toString());
223 }
224
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800225 public int rename(String oldname, String newname, boolean useEncryptedFilesystem) {
226 StringBuilder builder = new StringBuilder("rename");
227 builder.append(' ');
228 builder.append(oldname);
229 builder.append(' ');
230 builder.append(newname);
231 builder.append(' ');
232 if (useEncryptedFilesystem) {
233 builder.append('1');
234 } else {
235 builder.append('0');
236 }
237 return execute(builder.toString());
238 }
239
Oscar Montemayora8529f62009-11-18 10:14:20 -0800240 public int deleteCacheFiles(String name, boolean useEncryptedFilesystem) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 StringBuilder builder = new StringBuilder("rmcache");
242 builder.append(' ');
243 builder.append(name);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800244 builder.append(' ');
245 if (useEncryptedFilesystem) {
246 builder.append('1');
247 } else {
248 builder.append('0');
249 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 return execute(builder.toString());
251 }
252
Oscar Montemayora8529f62009-11-18 10:14:20 -0800253 public int clearUserData(String name, boolean useEncryptedFilesystem) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 StringBuilder builder = new StringBuilder("rmuserdata");
255 builder.append(' ');
256 builder.append(name);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800257 builder.append(' ');
258 if (useEncryptedFilesystem) {
259 builder.append('1');
260 } else {
261 builder.append('0');
262 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 return execute(builder.toString());
264 }
265
266 public boolean ping() {
267 if (execute("ping") < 0) {
268 return false;
269 } else {
270 return true;
271 }
272 }
273
274 public int freeCache(long freeStorageSize) {
275 StringBuilder builder = new StringBuilder("freecache");
276 builder.append(' ');
277 builder.append(String.valueOf(freeStorageSize));
278 return execute(builder.toString());
279 }
280
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800281 /*
282 * @param packagePathSuffix The name of the path relative to install
283 * directory. Say if the path name is /data/app/com.test-1.apk,
284 * the package suffix path will be com.test-1
285 */
286 public int setForwardLockPerm(String packagePathSuffix, int gid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 StringBuilder builder = new StringBuilder("protect");
288 builder.append(' ');
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800289 builder.append(packagePathSuffix);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 builder.append(' ');
291 builder.append(gid);
292 return execute(builder.toString());
293 }
294
295 public int getSizeInfo(String pkgName, String apkPath,
Oscar Montemayora8529f62009-11-18 10:14:20 -0800296 String fwdLockApkPath, PackageStats pStats, boolean useEncryptedFilesystem) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 StringBuilder builder = new StringBuilder("getsize");
298 builder.append(' ');
299 builder.append(pkgName);
300 builder.append(' ');
301 builder.append(apkPath);
302 builder.append(' ');
303 builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
Oscar Montemayora8529f62009-11-18 10:14:20 -0800304 builder.append(' ');
305 if (useEncryptedFilesystem) {
306 builder.append('1');
307 } else {
308 builder.append('0');
309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310
311 String s = transaction(builder.toString());
312 String res[] = s.split(" ");
313
314 if((res == null) || (res.length != 4)) {
315 return -1;
316 }
317 try {
318 pStats.codeSize = Long.parseLong(res[1]);
319 pStats.dataSize = Long.parseLong(res[2]);
320 pStats.cacheSize = Long.parseLong(res[3]);
321 return Integer.parseInt(res[0]);
322 } catch (NumberFormatException e) {
323 return -1;
324 }
325 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800326
327 public int moveFiles() {
328 return execute("movefiles");
329 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330}