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