blob: 1028b8941c49828778fa059bb14c54485ff6db56 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.net.LocalSocket;
Jason parks1125d782011-01-12 09:47:26 -060021import android.net.LocalSocketAddress;
Joe Onorato8a9b2202010-02-26 18:56:32 -080022import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
24import java.io.IOException;
25import java.io.InputStream;
26import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027
28class Installer {
29 private static final String TAG = "Installer";
30 InputStream mIn;
31 OutputStream mOut;
32 LocalSocket mSocket;
33
34 byte buf[] = new byte[1024];
35 int buflen = 0;
36
37 private boolean connect() {
38 if (mSocket != null) {
39 return true;
40 }
Joe Onorato8a9b2202010-02-26 18:56:32 -080041 Slog.i(TAG, "connecting...");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042 try {
43 mSocket = new LocalSocket();
44
45 LocalSocketAddress address = new LocalSocketAddress(
46 "installd", LocalSocketAddress.Namespace.RESERVED);
47
48 mSocket.connect(address);
49
50 mIn = mSocket.getInputStream();
51 mOut = mSocket.getOutputStream();
52 } catch (IOException ex) {
53 disconnect();
54 return false;
55 }
56 return true;
57 }
58
59 private void disconnect() {
Joe Onorato8a9b2202010-02-26 18:56:32 -080060 Slog.i(TAG,"disconnecting...");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 try {
62 if (mSocket != null) mSocket.close();
63 } catch (IOException ex) { }
64 try {
65 if (mIn != null) mIn.close();
66 } catch (IOException ex) { }
67 try {
68 if (mOut != null) mOut.close();
69 } catch (IOException ex) { }
70 mSocket = null;
71 mIn = null;
72 mOut = null;
73 }
74
75 private boolean readBytes(byte buffer[], int len) {
76 int off = 0, count;
77 if (len < 0) return false;
78 while (off != len) {
79 try {
80 count = mIn.read(buffer, off, len - off);
81 if (count <= 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -080082 Slog.e(TAG, "read error " + count);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 break;
84 }
85 off += count;
86 } catch (IOException ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -080087 Slog.e(TAG,"read exception");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 break;
89 }
90 }
Joe Onorato8a9b2202010-02-26 18:56:32 -080091// Slog.i(TAG, "read "+len+" bytes");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 if (off == len) return true;
93 disconnect();
94 return false;
95 }
96
97 private boolean readReply() {
98 int len;
99 buflen = 0;
100 if (!readBytes(buf, 2)) return false;
Jason parks1125d782011-01-12 09:47:26 -0600101 len = ((buf[0]) & 0xff) | (((buf[1]) & 0xff) << 8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 if ((len < 1) || (len > 1024)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800103 Slog.e(TAG,"invalid reply length ("+len+")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 disconnect();
105 return false;
106 }
107 if (!readBytes(buf, len)) return false;
108 buflen = len;
109 return true;
110 }
111
112 private boolean writeCommand(String _cmd) {
113 byte[] cmd = _cmd.getBytes();
114 int len = cmd.length;
115 if ((len < 1) || (len > 1024)) return false;
116 buf[0] = (byte) (len & 0xff);
117 buf[1] = (byte) ((len >> 8) & 0xff);
118 try {
119 mOut.write(buf, 0, 2);
120 mOut.write(cmd, 0, len);
121 } catch (IOException ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800122 Slog.e(TAG,"write error");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 disconnect();
124 return false;
125 }
126 return true;
127 }
128
129 private synchronized String transaction(String cmd) {
130 if (!connect()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800131 Slog.e(TAG, "connection failed");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 return "-1";
133 }
134
135 if (!writeCommand(cmd)) {
136 /* If installd died and restarted in the background
137 * (unlikely but possible) we'll fail on the next
138 * write (this one). Try to reconnect and write
139 * the command one more time before giving up.
140 */
Joe Onorato8a9b2202010-02-26 18:56:32 -0800141 Slog.e(TAG, "write command failed? reconnect!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 if (!connect() || !writeCommand(cmd)) {
143 return "-1";
144 }
145 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800146// Slog.i(TAG,"send: '"+cmd+"'");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 if (readReply()) {
148 String s = new String(buf, 0, buflen);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800149// Slog.i(TAG,"recv: '"+s+"'");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 return s;
151 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800152// Slog.i(TAG,"fail");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 return "-1";
154 }
155 }
156
157 private int execute(String cmd) {
158 String res = transaction(cmd);
159 try {
160 return Integer.parseInt(res);
161 } catch (NumberFormatException ex) {
162 return -1;
163 }
164 }
165
Jason parks1125d782011-01-12 09:47:26 -0600166 public int install(String name, int uid, int gid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 StringBuilder builder = new StringBuilder("install");
168 builder.append(' ');
169 builder.append(name);
170 builder.append(' ');
171 builder.append(uid);
172 builder.append(' ');
173 builder.append(gid);
174 return execute(builder.toString());
175 }
176
177 public int dexopt(String apkPath, int uid, boolean isPublic) {
178 StringBuilder builder = new StringBuilder("dexopt");
179 builder.append(' ');
180 builder.append(apkPath);
181 builder.append(' ');
182 builder.append(uid);
183 builder.append(isPublic ? " 1" : " 0");
184 return execute(builder.toString());
185 }
186
187 public int movedex(String srcPath, String dstPath) {
188 StringBuilder builder = new StringBuilder("movedex");
189 builder.append(' ');
190 builder.append(srcPath);
191 builder.append(' ');
192 builder.append(dstPath);
193 return execute(builder.toString());
194 }
195
196 public int rmdex(String codePath) {
197 StringBuilder builder = new StringBuilder("rmdex");
198 builder.append(' ');
199 builder.append(codePath);
200 return execute(builder.toString());
201 }
202
Jason parks1125d782011-01-12 09:47:26 -0600203 public int remove(String name) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 StringBuilder builder = new StringBuilder("remove");
205 builder.append(' ');
206 builder.append(name);
207 return execute(builder.toString());
208 }
209
Jason parks1125d782011-01-12 09:47:26 -0600210 public int rename(String oldname, String newname) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800211 StringBuilder builder = new StringBuilder("rename");
212 builder.append(' ');
213 builder.append(oldname);
214 builder.append(' ');
215 builder.append(newname);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800216 return execute(builder.toString());
217 }
218
Jason parks1125d782011-01-12 09:47:26 -0600219 public int deleteCacheFiles(String name) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 StringBuilder builder = new StringBuilder("rmcache");
221 builder.append(' ');
222 builder.append(name);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800223 builder.append(' ');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 return execute(builder.toString());
225 }
226
Jason parks1125d782011-01-12 09:47:26 -0600227 public int clearUserData(String name) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 StringBuilder builder = new StringBuilder("rmuserdata");
229 builder.append(' ');
230 builder.append(name);
231 return execute(builder.toString());
232 }
233
234 public boolean ping() {
235 if (execute("ping") < 0) {
236 return false;
237 } else {
238 return true;
239 }
240 }
241
242 public int freeCache(long freeStorageSize) {
243 StringBuilder builder = new StringBuilder("freecache");
244 builder.append(' ');
245 builder.append(String.valueOf(freeStorageSize));
246 return execute(builder.toString());
247 }
248
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800249 /*
250 * @param packagePathSuffix The name of the path relative to install
251 * directory. Say if the path name is /data/app/com.test-1.apk,
252 * the package suffix path will be com.test-1
253 */
254 public int setForwardLockPerm(String packagePathSuffix, int gid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 StringBuilder builder = new StringBuilder("protect");
256 builder.append(' ');
Suchi Amalapurapuc028be42010-01-25 12:19:12 -0800257 builder.append(packagePathSuffix);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 builder.append(' ');
259 builder.append(gid);
260 return execute(builder.toString());
261 }
262
Jason parks1125d782011-01-12 09:47:26 -0600263 public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath,
264 PackageStats pStats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 StringBuilder builder = new StringBuilder("getsize");
266 builder.append(' ');
267 builder.append(pkgName);
268 builder.append(' ');
269 builder.append(apkPath);
270 builder.append(' ');
271 builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272
273 String s = transaction(builder.toString());
274 String res[] = s.split(" ");
275
276 if((res == null) || (res.length != 4)) {
277 return -1;
278 }
279 try {
280 pStats.codeSize = Long.parseLong(res[1]);
281 pStats.dataSize = Long.parseLong(res[2]);
282 pStats.cacheSize = Long.parseLong(res[3]);
283 return Integer.parseInt(res[0]);
284 } catch (NumberFormatException e) {
285 return -1;
286 }
287 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800288
289 public int moveFiles() {
290 return execute("movefiles");
291 }
Kenny Root6a6b0072010-10-07 16:46:10 -0700292
293 public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath) {
294 if (dataPath == null) {
295 Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
296 return -1;
297 } else if (nativeLibPath == null) {
298 Slog.e(TAG, "unlinkNativeLibraryDirectory nativeLibPath is null");
299 return -1;
300 }
301
302 StringBuilder builder = new StringBuilder("linklib ");
303 builder.append(dataPath);
304 builder.append(' ');
305 builder.append(nativeLibPath);
306
307 return execute(builder.toString());
308 }
309
310 public int unlinkNativeLibraryDirectory(String dataPath) {
311 if (dataPath == null) {
312 Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
313 return -1;
314 }
315
316 StringBuilder builder = new StringBuilder("unlinklib ");
317 builder.append(dataPath);
318
319 return execute(builder.toString());
320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321}