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