Installer.java revision 29564cd24589867f653cd22cabbaac6493cfc530
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.pm;
18
19import android.content.Context;
20import android.content.pm.PackageStats;
21import android.os.Build;
22import android.util.Slog;
23import dalvik.system.VMRuntime;
24
25import com.android.internal.os.InstallerConnection;
26import com.android.server.SystemService;
27
28public final class Installer extends SystemService {
29    private static final String TAG = "Installer";
30
31    private final InstallerConnection mInstaller;
32
33    public Installer(Context context) {
34        super(context);
35        mInstaller = new InstallerConnection();
36    }
37
38    @Override
39    public void onStart() {
40        Slog.i(TAG, "Waiting for installd to be ready.");
41        ping();
42    }
43
44    public int install(String name, int uid, int gid, String seinfo) {
45        StringBuilder builder = new StringBuilder("install");
46        builder.append(' ');
47        builder.append(name);
48        builder.append(' ');
49        builder.append(uid);
50        builder.append(' ');
51        builder.append(gid);
52        builder.append(' ');
53        builder.append(seinfo != null ? seinfo : "!");
54        return mInstaller.execute(builder.toString());
55    }
56
57    public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
58            String instructionSet) {
59        if (!isValidInstructionSet(instructionSet)) {
60            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
61            return -1;
62        }
63
64        StringBuilder builder = new StringBuilder("patchoat");
65        builder.append(' ');
66        builder.append(apkPath);
67        builder.append(' ');
68        builder.append(uid);
69        builder.append(isPublic ? " 1" : " 0");
70        builder.append(' ');
71        builder.append(pkgName);
72        builder.append(' ');
73        builder.append(instructionSet);
74        return mInstaller.execute(builder.toString());
75    }
76
77    public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
78        if (!isValidInstructionSet(instructionSet)) {
79            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
80            return -1;
81        }
82
83        return mInstaller.patchoat(apkPath, uid, isPublic, instructionSet);
84    }
85
86    public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
87        if (!isValidInstructionSet(instructionSet)) {
88            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
89            return -1;
90        }
91
92        return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet);
93    }
94
95    public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
96            String instructionSet) {
97        if (!isValidInstructionSet(instructionSet)) {
98            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
99            return -1;
100        }
101
102        StringBuilder builder = new StringBuilder("dexopt");
103        builder.append(' ');
104        builder.append(apkPath);
105        builder.append(' ');
106        builder.append(uid);
107        builder.append(isPublic ? " 1" : " 0");
108        builder.append(' ');
109        builder.append(pkgName);
110        builder.append(' ');
111        builder.append(instructionSet);
112        return mInstaller.execute(builder.toString());
113    }
114
115    public int idmap(String targetApkPath, String overlayApkPath, int uid) {
116        StringBuilder builder = new StringBuilder("idmap");
117        builder.append(' ');
118        builder.append(targetApkPath);
119        builder.append(' ');
120        builder.append(overlayApkPath);
121        builder.append(' ');
122        builder.append(uid);
123        return mInstaller.execute(builder.toString());
124    }
125
126    public int movedex(String srcPath, String dstPath, String instructionSet) {
127        if (!isValidInstructionSet(instructionSet)) {
128            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
129            return -1;
130        }
131
132        StringBuilder builder = new StringBuilder("movedex");
133        builder.append(' ');
134        builder.append(srcPath);
135        builder.append(' ');
136        builder.append(dstPath);
137        builder.append(' ');
138        builder.append(instructionSet);
139        return mInstaller.execute(builder.toString());
140    }
141
142    public int rmdex(String codePath, String instructionSet) {
143        if (!isValidInstructionSet(instructionSet)) {
144            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
145            return -1;
146        }
147
148        StringBuilder builder = new StringBuilder("rmdex");
149        builder.append(' ');
150        builder.append(codePath);
151        builder.append(' ');
152        builder.append(instructionSet);
153        return mInstaller.execute(builder.toString());
154    }
155
156    public int remove(String name, int userId) {
157        StringBuilder builder = new StringBuilder("remove");
158        builder.append(' ');
159        builder.append(name);
160        builder.append(' ');
161        builder.append(userId);
162        return mInstaller.execute(builder.toString());
163    }
164
165    public int rename(String oldname, String newname) {
166        StringBuilder builder = new StringBuilder("rename");
167        builder.append(' ');
168        builder.append(oldname);
169        builder.append(' ');
170        builder.append(newname);
171        return mInstaller.execute(builder.toString());
172    }
173
174    public int fixUid(String name, int uid, int gid) {
175        StringBuilder builder = new StringBuilder("fixuid");
176        builder.append(' ');
177        builder.append(name);
178        builder.append(' ');
179        builder.append(uid);
180        builder.append(' ');
181        builder.append(gid);
182        return mInstaller.execute(builder.toString());
183    }
184
185    public int deleteCacheFiles(String name, int userId) {
186        StringBuilder builder = new StringBuilder("rmcache");
187        builder.append(' ');
188        builder.append(name);
189        builder.append(' ');
190        builder.append(userId);
191        return mInstaller.execute(builder.toString());
192    }
193
194    public int deleteCodeCacheFiles(String name, int userId) {
195        StringBuilder builder = new StringBuilder("rmcodecache");
196        builder.append(' ');
197        builder.append(name);
198        builder.append(' ');
199        builder.append(userId);
200        return mInstaller.execute(builder.toString());
201    }
202
203    public int createUserData(String name, int uid, int userId, String seinfo) {
204        StringBuilder builder = new StringBuilder("mkuserdata");
205        builder.append(' ');
206        builder.append(name);
207        builder.append(' ');
208        builder.append(uid);
209        builder.append(' ');
210        builder.append(userId);
211        builder.append(' ');
212        builder.append(seinfo != null ? seinfo : "!");
213        return mInstaller.execute(builder.toString());
214    }
215
216    public int createUserConfig(int userId) {
217        StringBuilder builder = new StringBuilder("mkuserconfig");
218        builder.append(' ');
219        builder.append(userId);
220        return mInstaller.execute(builder.toString());
221    }
222
223    public int removeUserDataDirs(int userId) {
224        StringBuilder builder = new StringBuilder("rmuser");
225        builder.append(' ');
226        builder.append(userId);
227        return mInstaller.execute(builder.toString());
228    }
229
230    public int clearUserData(String name, int userId) {
231        StringBuilder builder = new StringBuilder("rmuserdata");
232        builder.append(' ');
233        builder.append(name);
234        builder.append(' ');
235        builder.append(userId);
236        return mInstaller.execute(builder.toString());
237    }
238
239    public boolean ping() {
240        if (mInstaller.execute("ping") < 0) {
241            return false;
242        } else {
243            return true;
244        }
245    }
246
247    public int pruneDexCache(String cacheSubDir) {
248        return mInstaller.execute("prunedexcache " + cacheSubDir);
249    }
250
251    public int freeCache(long freeStorageSize) {
252        StringBuilder builder = new StringBuilder("freecache");
253        builder.append(' ');
254        builder.append(String.valueOf(freeStorageSize));
255        return mInstaller.execute(builder.toString());
256    }
257
258    public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
259            String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
260        for (String instructionSet : instructionSets) {
261            if (!isValidInstructionSet(instructionSet)) {
262                Slog.e(TAG, "Invalid instruction set: " + instructionSet);
263                return -1;
264            }
265        }
266
267        StringBuilder builder = new StringBuilder("getsize");
268        builder.append(' ');
269        builder.append(pkgName);
270        builder.append(' ');
271        builder.append(persona);
272        builder.append(' ');
273        builder.append(apkPath);
274        builder.append(' ');
275        // TODO: Extend getSizeInfo to look at the full subdirectory tree,
276        // not just the first level.
277        builder.append(libDirPath != null ? libDirPath : "!");
278        builder.append(' ');
279        builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
280        builder.append(' ');
281        builder.append(asecPath != null ? asecPath : "!");
282        builder.append(' ');
283        // TODO: Extend getSizeInfo to look at *all* instrution sets, not
284        // just the primary.
285        builder.append(instructionSets[0]);
286
287        String s = mInstaller.transact(builder.toString());
288        String res[] = s.split(" ");
289
290        if ((res == null) || (res.length != 5)) {
291            return -1;
292        }
293        try {
294            pStats.codeSize = Long.parseLong(res[1]);
295            pStats.dataSize = Long.parseLong(res[2]);
296            pStats.cacheSize = Long.parseLong(res[3]);
297            pStats.externalCodeSize = Long.parseLong(res[4]);
298            return Integer.parseInt(res[0]);
299        } catch (NumberFormatException e) {
300            return -1;
301        }
302    }
303
304    public int moveFiles() {
305        return mInstaller.execute("movefiles");
306    }
307
308    /**
309     * Links the 32 bit native library directory in an application's data directory to the
310     * real location for backward compatibility. Note that no such symlink is created for
311     * 64 bit shared libraries.
312     *
313     * @return -1 on error
314     */
315    public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
316        if (dataPath == null) {
317            Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
318            return -1;
319        } else if (nativeLibPath32 == null) {
320            Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");
321            return -1;
322        }
323
324        StringBuilder builder = new StringBuilder("linklib ");
325        builder.append(dataPath);
326        builder.append(' ');
327        builder.append(nativeLibPath32);
328        builder.append(' ');
329        builder.append(userId);
330
331        return mInstaller.execute(builder.toString());
332    }
333
334    public boolean restoreconData(String pkgName, String seinfo, int uid) {
335        StringBuilder builder = new StringBuilder("restorecondata");
336        builder.append(' ');
337        builder.append(pkgName);
338        builder.append(' ');
339        builder.append(seinfo != null ? seinfo : "!");
340        builder.append(' ');
341        builder.append(uid);
342        return (mInstaller.execute(builder.toString()) == 0);
343    }
344
345    /**
346     * Returns true iff. {@code instructionSet} is a valid instruction set.
347     */
348    private static boolean isValidInstructionSet(String instructionSet) {
349        if (instructionSet == null) {
350            return false;
351        }
352
353        for (String abi : Build.SUPPORTED_ABIS) {
354            if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) {
355                return true;
356            }
357        }
358
359        return false;
360    }
361}
362