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