Installer.java revision 4f05cd8900bfb559d5de58b86fa01f07bddafb2c
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.os.IInstalld;
24import android.os.RemoteException;
25import android.os.ServiceManager;
26import android.os.ServiceSpecificException;
27import android.util.Slog;
28
29import com.android.server.SystemService;
30
31import dalvik.system.VMRuntime;
32
33public class Installer extends SystemService {
34    private static final String TAG = "Installer";
35
36    /* ***************************************************************************
37     * IMPORTANT: These values are passed to native code. Keep them in sync with
38     * frameworks/native/cmds/installd/installd.h
39     * **************************************************************************/
40    /** Application should be visible to everyone */
41    public static final int DEXOPT_PUBLIC         = 1 << 1;
42    /** Application wants to run in VM safe mode */
43    public static final int DEXOPT_SAFEMODE       = 1 << 2;
44    /** Application wants to allow debugging of its code */
45    public static final int DEXOPT_DEBUGGABLE     = 1 << 3;
46    /** The system boot has finished */
47    public static final int DEXOPT_BOOTCOMPLETE   = 1 << 4;
48    /** Hint that the dexopt type is profile-guided. */
49    public static final int DEXOPT_PROFILE_GUIDED = 1 << 5;
50
51    // NOTE: keep in sync with installd
52    public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
53    public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
54
55    private final boolean mIsolated;
56
57    // TODO: reconnect if installd restarts
58    private volatile IInstalld mInstalld;
59    private volatile Object mWarnIfHeld;
60
61    public Installer(Context context) {
62        this(context, false);
63    }
64
65    /**
66     * @param isolated indicates if this object should <em>not</em> connect to
67     *            the real {@code installd}. All remote calls will be ignored
68     *            unless you extend this class and intercept them.
69     */
70    public Installer(Context context, boolean isolated) {
71        super(context);
72        mIsolated = isolated;
73    }
74
75    /**
76     * Yell loudly if someone tries making future calls while holding a lock on
77     * the given object.
78     */
79    public void setWarnIfHeld(Object warnIfHeld) {
80        mWarnIfHeld = warnIfHeld;
81    }
82
83    @Override
84    public void onStart() {
85        if (mIsolated) {
86            mInstalld = null;
87        } else {
88            mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd"));
89        }
90    }
91
92    /**
93     * Do several pre-flight checks before making a remote call.
94     *
95     * @return if the remote call should continue.
96     */
97    private boolean checkBeforeRemote() {
98        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
99            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
100                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
101        }
102        if (mIsolated) {
103            Slog.i(TAG, "Ignoring request because this installer is isolated");
104            return false;
105        } else {
106            return true;
107        }
108    }
109
110    public void createAppData(String uuid, String packageName, int userId, int flags, int appId,
111            String seInfo, int targetSdkVersion) throws InstallerException {
112        if (!checkBeforeRemote()) return;
113        try {
114            mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
115                    targetSdkVersion);
116        } catch (RemoteException | ServiceSpecificException e) {
117            throw InstallerException.from(e);
118        }
119    }
120
121    public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId,
122            String seInfo) throws InstallerException {
123        if (!checkBeforeRemote()) return;
124        try {
125            mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo);
126        } catch (RemoteException | ServiceSpecificException e) {
127            throw InstallerException.from(e);
128        }
129    }
130
131    public void migrateAppData(String uuid, String packageName, int userId, int flags)
132            throws InstallerException {
133        if (!checkBeforeRemote()) return;
134        try {
135            mInstalld.migrateAppData(uuid, packageName, userId, flags);
136        } catch (RemoteException | ServiceSpecificException e) {
137            throw InstallerException.from(e);
138        }
139    }
140
141    public void clearAppData(String uuid, String packageName, int userId, int flags,
142            long ceDataInode) throws InstallerException {
143        if (!checkBeforeRemote()) return;
144        try {
145            mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode);
146        } catch (RemoteException | ServiceSpecificException e) {
147            throw InstallerException.from(e);
148        }
149    }
150
151    public void destroyAppData(String uuid, String packageName, int userId, int flags,
152            long ceDataInode) throws InstallerException {
153        if (!checkBeforeRemote()) return;
154        try {
155            mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode);
156        } catch (RemoteException | ServiceSpecificException e) {
157            throw InstallerException.from(e);
158        }
159    }
160
161    public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
162            String dataAppName, int appId, String seInfo, int targetSdkVersion)
163            throws InstallerException {
164        if (!checkBeforeRemote()) return;
165        try {
166            mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo,
167                    targetSdkVersion);
168        } catch (RemoteException | ServiceSpecificException e) {
169            throw InstallerException.from(e);
170        }
171    }
172
173    public void getAppSize(String uuid, String packageName, int userId, int flags, long ceDataInode,
174            String codePath, PackageStats stats) throws InstallerException {
175        if (!checkBeforeRemote()) return;
176        try {
177            final long[] res = mInstalld.getAppSize(uuid, packageName, userId, flags, ceDataInode,
178                    codePath);
179            stats.codeSize += res[0];
180            stats.dataSize += res[1];
181            stats.cacheSize += res[2];
182        } catch (RemoteException | ServiceSpecificException e) {
183            throw InstallerException.from(e);
184        }
185    }
186
187    public long getAppDataInode(String uuid, String packageName, int userId, int flags)
188            throws InstallerException {
189        if (!checkBeforeRemote()) return -1;
190        try {
191            return mInstalld.getAppDataInode(uuid, packageName, userId, flags);
192        } catch (RemoteException | ServiceSpecificException e) {
193            throw InstallerException.from(e);
194        }
195    }
196
197    public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
198            int dexoptNeeded, @Nullable String outputPath, int dexFlags,
199            String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries)
200            throws InstallerException {
201        assertValidInstructionSet(instructionSet);
202        if (!checkBeforeRemote()) return;
203        try {
204            mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
205                    dexFlags, compilerFilter, volumeUuid, sharedLibraries);
206        } catch (RemoteException | ServiceSpecificException e) {
207            throw InstallerException.from(e);
208        }
209    }
210
211    public boolean mergeProfiles(int uid, String packageName) throws InstallerException {
212        if (!checkBeforeRemote()) return false;
213        try {
214            return mInstalld.mergeProfiles(uid, packageName);
215        } catch (RemoteException | ServiceSpecificException e) {
216            throw InstallerException.from(e);
217        }
218    }
219
220    public boolean dumpProfiles(int uid, String packageName, String codePaths)
221            throws InstallerException {
222        if (!checkBeforeRemote()) return false;
223        try {
224            return mInstalld.dumpProfiles(uid, packageName, codePaths);
225        } catch (RemoteException | ServiceSpecificException e) {
226            throw InstallerException.from(e);
227        }
228    }
229
230    public void idmap(String targetApkPath, String overlayApkPath, int uid)
231            throws InstallerException {
232        if (!checkBeforeRemote()) return;
233        try {
234            mInstalld.idmap(targetApkPath, overlayApkPath, uid);
235        } catch (RemoteException | ServiceSpecificException e) {
236            throw InstallerException.from(e);
237        }
238    }
239
240    public void rmdex(String codePath, String instructionSet) throws InstallerException {
241        assertValidInstructionSet(instructionSet);
242        if (!checkBeforeRemote()) return;
243        try {
244            mInstalld.rmdex(codePath, instructionSet);
245        } catch (RemoteException | ServiceSpecificException e) {
246            throw InstallerException.from(e);
247        }
248    }
249
250    public void rmPackageDir(String packageDir) throws InstallerException {
251        if (!checkBeforeRemote()) return;
252        try {
253            mInstalld.rmPackageDir(packageDir);
254        } catch (RemoteException | ServiceSpecificException e) {
255            throw InstallerException.from(e);
256        }
257    }
258
259    public void clearAppProfiles(String packageName) throws InstallerException {
260        if (!checkBeforeRemote()) return;
261        try {
262            mInstalld.clearAppProfiles(packageName);
263        } catch (RemoteException | ServiceSpecificException e) {
264            throw InstallerException.from(e);
265        }
266    }
267
268    public void destroyAppProfiles(String packageName) throws InstallerException {
269        if (!checkBeforeRemote()) return;
270        try {
271            mInstalld.destroyAppProfiles(packageName);
272        } catch (RemoteException | ServiceSpecificException e) {
273            throw InstallerException.from(e);
274        }
275    }
276
277    public void createUserData(String uuid, int userId, int userSerial, int flags)
278            throws InstallerException {
279        if (!checkBeforeRemote()) return;
280        try {
281            mInstalld.createUserData(uuid, userId, userSerial, flags);
282        } catch (RemoteException | ServiceSpecificException e) {
283            throw InstallerException.from(e);
284        }
285    }
286
287    public void destroyUserData(String uuid, int userId, int flags) throws InstallerException {
288        if (!checkBeforeRemote()) return;
289        try {
290            mInstalld.destroyUserData(uuid, userId, flags);
291        } catch (RemoteException | ServiceSpecificException e) {
292            throw InstallerException.from(e);
293        }
294    }
295
296    public void markBootComplete(String instructionSet) throws InstallerException {
297        assertValidInstructionSet(instructionSet);
298        if (!checkBeforeRemote()) return;
299        try {
300            mInstalld.markBootComplete(instructionSet);
301        } catch (RemoteException | ServiceSpecificException e) {
302            throw InstallerException.from(e);
303        }
304    }
305
306    public void freeCache(String uuid, long freeStorageSize) throws InstallerException {
307        if (!checkBeforeRemote()) return;
308        try {
309            mInstalld.freeCache(uuid, freeStorageSize);
310        } catch (RemoteException | ServiceSpecificException e) {
311            throw InstallerException.from(e);
312        }
313    }
314
315    /**
316     * Links the 32 bit native library directory in an application's data
317     * directory to the real location for backward compatibility. Note that no
318     * such symlink is created for 64 bit shared libraries.
319     */
320    public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32,
321            int userId) throws InstallerException {
322        if (!checkBeforeRemote()) return;
323        try {
324            mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId);
325        } catch (RemoteException | ServiceSpecificException e) {
326            throw InstallerException.from(e);
327        }
328    }
329
330    public void createOatDir(String oatDir, String dexInstructionSet)
331            throws InstallerException {
332        if (!checkBeforeRemote()) return;
333        try {
334            mInstalld.createOatDir(oatDir, dexInstructionSet);
335        } catch (RemoteException | ServiceSpecificException e) {
336            throw InstallerException.from(e);
337        }
338    }
339
340    public void linkFile(String relativePath, String fromBase, String toBase)
341            throws InstallerException {
342        if (!checkBeforeRemote()) return;
343        try {
344            mInstalld.linkFile(relativePath, fromBase, toBase);
345        } catch (RemoteException | ServiceSpecificException e) {
346            throw InstallerException.from(e);
347        }
348    }
349
350    public void moveAb(String apkPath, String instructionSet, String outputPath)
351            throws InstallerException {
352        if (!checkBeforeRemote()) return;
353        try {
354            mInstalld.moveAb(apkPath, instructionSet, outputPath);
355        } catch (RemoteException | ServiceSpecificException e) {
356            throw InstallerException.from(e);
357        }
358    }
359
360    public void deleteOdex(String apkPath, String instructionSet, String outputPath)
361            throws InstallerException {
362        if (!checkBeforeRemote()) return;
363        try {
364            mInstalld.deleteOdex(apkPath, instructionSet, outputPath);
365        } catch (RemoteException | ServiceSpecificException e) {
366            throw InstallerException.from(e);
367        }
368    }
369
370    private static void assertValidInstructionSet(String instructionSet)
371            throws InstallerException {
372        for (String abi : Build.SUPPORTED_ABIS) {
373            if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) {
374                return;
375            }
376        }
377        throw new InstallerException("Invalid instruction set: " + instructionSet);
378    }
379
380    public static class InstallerException extends Exception {
381        public InstallerException(String detailMessage) {
382            super(detailMessage);
383        }
384
385        public static InstallerException from(Exception e) throws InstallerException {
386            throw new InstallerException(e.getMessage());
387        }
388    }
389}
390