• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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