• 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 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)191     public int install(String name, int uid, int gid) {
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         return execute(builder.toString());
200     }
201 
dexopt(String apkPath, int uid, boolean isPublic)202     public int dexopt(String apkPath, int uid, boolean isPublic) {
203         StringBuilder builder = new StringBuilder("dexopt");
204         builder.append(' ');
205         builder.append(apkPath);
206         builder.append(' ');
207         builder.append(uid);
208         builder.append(isPublic ? " 1" : " 0");
209         return execute(builder.toString());
210     }
211 
movedex(String srcPath, String dstPath)212     public int movedex(String srcPath, String dstPath) {
213         StringBuilder builder = new StringBuilder("movedex");
214         builder.append(' ');
215         builder.append(srcPath);
216         builder.append(' ');
217         builder.append(dstPath);
218         return execute(builder.toString());
219     }
220 
rmdex(String codePath)221     public int rmdex(String codePath) {
222         StringBuilder builder = new StringBuilder("rmdex");
223         builder.append(' ');
224         builder.append(codePath);
225         return execute(builder.toString());
226     }
227 
remove(String name, int userId)228     public int remove(String name, int userId) {
229         StringBuilder builder = new StringBuilder("remove");
230         builder.append(' ');
231         builder.append(name);
232         builder.append(' ');
233         builder.append(userId);
234         return execute(builder.toString());
235     }
236 
rename(String oldname, String newname)237     public int rename(String oldname, String newname) {
238         StringBuilder builder = new StringBuilder("rename");
239         builder.append(' ');
240         builder.append(oldname);
241         builder.append(' ');
242         builder.append(newname);
243         return execute(builder.toString());
244     }
245 
fixUid(String name, int uid, int gid)246     public int fixUid(String name, int uid, int gid) {
247         StringBuilder builder = new StringBuilder("fixuid");
248         builder.append(' ');
249         builder.append(name);
250         builder.append(' ');
251         builder.append(uid);
252         builder.append(' ');
253         builder.append(gid);
254         return execute(builder.toString());
255     }
256 
deleteCacheFiles(String name)257     public int deleteCacheFiles(String name) {
258         StringBuilder builder = new StringBuilder("rmcache");
259         builder.append(' ');
260         builder.append(name);
261         return execute(builder.toString());
262     }
263 
createUserData(String name, int uid, int userId)264     public int createUserData(String name, int uid, int userId) {
265         StringBuilder builder = new StringBuilder("mkuserdata");
266         builder.append(' ');
267         builder.append(name);
268         builder.append(' ');
269         builder.append(uid);
270         builder.append(' ');
271         builder.append(userId);
272         return execute(builder.toString());
273     }
274 
removeUserDataDirs(int userId)275     public int removeUserDataDirs(int userId) {
276         StringBuilder builder = new StringBuilder("rmuser");
277         builder.append(' ');
278         builder.append(userId);
279         return execute(builder.toString());
280     }
281 
clearUserData(String name, int userId)282     public int clearUserData(String name, int userId) {
283         StringBuilder builder = new StringBuilder("rmuserdata");
284         builder.append(' ');
285         builder.append(name);
286         builder.append(' ');
287         builder.append(userId);
288         return execute(builder.toString());
289     }
290 
291     /**
292      * Clone all the package data directories from srcUserId to targetUserId. If copyData is true,
293      * some of the data is also copied, otherwise just empty directories are created with the
294      * correct access rights.
295      * @param srcUserId user to copy the data directories from
296      * @param targetUserId user to copy the data directories to
297      * @param copyData whether the data itself is to be copied. If false, empty directories are
298      * created.
299      * @return success/error code
300      */
cloneUserData(int srcUserId, int targetUserId, boolean copyData)301     public int cloneUserData(int srcUserId, int targetUserId, boolean copyData) {
302         StringBuilder builder = new StringBuilder("cloneuserdata");
303         builder.append(' ');
304         builder.append(srcUserId);
305         builder.append(' ');
306         builder.append(targetUserId);
307         builder.append(' ');
308         builder.append(copyData ? '1' : '0');
309         return execute(builder.toString());
310     }
311 
ping()312     public boolean ping() {
313         if (execute("ping") < 0) {
314             return false;
315         } else {
316             return true;
317         }
318     }
319 
freeCache(long freeStorageSize)320     public int freeCache(long freeStorageSize) {
321         StringBuilder builder = new StringBuilder("freecache");
322         builder.append(' ');
323         builder.append(String.valueOf(freeStorageSize));
324         return execute(builder.toString());
325     }
326 
327     /*
328      * @param packagePathSuffix The name of the path relative to install
329      * directory. Say if the path name is /data/app/com.test-1.apk, the package
330      * suffix path will be com.test-1
331      */
setForwardLockPerm(String packagePathSuffix, int gid)332     public int setForwardLockPerm(String packagePathSuffix, int gid) {
333         StringBuilder builder = new StringBuilder("protect");
334         builder.append(' ');
335         builder.append(packagePathSuffix);
336         builder.append(' ');
337         builder.append(gid);
338         return execute(builder.toString());
339     }
340 
getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath, String asecPath, PackageStats pStats)341     public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath,
342             String asecPath, PackageStats pStats) {
343         StringBuilder builder = new StringBuilder("getsize");
344         builder.append(' ');
345         builder.append(pkgName);
346         builder.append(' ');
347         builder.append(apkPath);
348         builder.append(' ');
349         builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
350         builder.append(' ');
351         builder.append(asecPath != null ? asecPath : "!");
352 
353         String s = transaction(builder.toString());
354         String res[] = s.split(" ");
355 
356         if ((res == null) || (res.length != 5)) {
357             return -1;
358         }
359         try {
360             pStats.codeSize = Long.parseLong(res[1]);
361             pStats.dataSize = Long.parseLong(res[2]);
362             pStats.cacheSize = Long.parseLong(res[3]);
363             pStats.externalCodeSize = Long.parseLong(res[4]);
364             return Integer.parseInt(res[0]);
365         } catch (NumberFormatException e) {
366             return -1;
367         }
368     }
369 
moveFiles()370     public int moveFiles() {
371         return execute("movefiles");
372     }
373 
linkNativeLibraryDirectory(String dataPath, String nativeLibPath)374     public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath) {
375         if (dataPath == null) {
376             Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
377             return -1;
378         } else if (nativeLibPath == null) {
379             Slog.e(TAG, "unlinkNativeLibraryDirectory nativeLibPath is null");
380             return -1;
381         }
382 
383         StringBuilder builder = new StringBuilder("linklib ");
384         builder.append(dataPath);
385         builder.append(' ');
386         builder.append(nativeLibPath);
387 
388         return execute(builder.toString());
389     }
390 
unlinkNativeLibraryDirectory(String dataPath)391     public int unlinkNativeLibraryDirectory(String dataPath) {
392         if (dataPath == null) {
393             Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
394             return -1;
395         }
396 
397         StringBuilder builder = new StringBuilder("unlinklib ");
398         builder.append(dataPath);
399 
400         return execute(builder.toString());
401     }
402 }
403