Installer.java revision 1aa5f88e35734383e66ecd65e82e83d788e18ccb
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 removeIdmap(String overlayApkPath) throws InstallerException {
307        if (!checkBeforeRemote()) return;
308        try {
309            mInstalld.removeIdmap(overlayApkPath);
310        } catch (Exception e) {
311            throw InstallerException.from(e);
312        }
313    }
314
315    public void rmdex(String codePath, String instructionSet) throws InstallerException {
316        assertValidInstructionSet(instructionSet);
317        if (!checkBeforeRemote()) return;
318        try {
319            mInstalld.rmdex(codePath, instructionSet);
320        } catch (Exception e) {
321            throw InstallerException.from(e);
322        }
323    }
324
325    public void rmPackageDir(String packageDir) throws InstallerException {
326        if (!checkBeforeRemote()) return;
327        try {
328            mInstalld.rmPackageDir(packageDir);
329        } catch (Exception e) {
330            throw InstallerException.from(e);
331        }
332    }
333
334    public void clearAppProfiles(String packageName) throws InstallerException {
335        if (!checkBeforeRemote()) return;
336        try {
337            mInstalld.clearAppProfiles(packageName);
338        } catch (Exception e) {
339            throw InstallerException.from(e);
340        }
341    }
342
343    public void destroyAppProfiles(String packageName) throws InstallerException {
344        if (!checkBeforeRemote()) return;
345        try {
346            mInstalld.destroyAppProfiles(packageName);
347        } catch (Exception e) {
348            throw InstallerException.from(e);
349        }
350    }
351
352    public void createUserData(String uuid, int userId, int userSerial, int flags)
353            throws InstallerException {
354        if (!checkBeforeRemote()) return;
355        try {
356            mInstalld.createUserData(uuid, userId, userSerial, flags);
357        } catch (Exception e) {
358            throw InstallerException.from(e);
359        }
360    }
361
362    public void destroyUserData(String uuid, int userId, int flags) throws InstallerException {
363        if (!checkBeforeRemote()) return;
364        try {
365            mInstalld.destroyUserData(uuid, userId, flags);
366        } catch (Exception e) {
367            throw InstallerException.from(e);
368        }
369    }
370
371    public void markBootComplete(String instructionSet) throws InstallerException {
372        assertValidInstructionSet(instructionSet);
373        if (!checkBeforeRemote()) return;
374        try {
375            mInstalld.markBootComplete(instructionSet);
376        } catch (Exception e) {
377            throw InstallerException.from(e);
378        }
379    }
380
381    public void freeCache(String uuid, long freeStorageSize, int flags) throws InstallerException {
382        if (!checkBeforeRemote()) return;
383        try {
384            mInstalld.freeCache(uuid, freeStorageSize, flags);
385        } catch (Exception e) {
386            throw InstallerException.from(e);
387        }
388    }
389
390    /**
391     * Links the 32 bit native library directory in an application's data
392     * directory to the real location for backward compatibility. Note that no
393     * such symlink is created for 64 bit shared libraries.
394     */
395    public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32,
396            int userId) throws InstallerException {
397        if (!checkBeforeRemote()) return;
398        try {
399            mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId);
400        } catch (Exception e) {
401            throw InstallerException.from(e);
402        }
403    }
404
405    public void createOatDir(String oatDir, String dexInstructionSet)
406            throws InstallerException {
407        if (!checkBeforeRemote()) return;
408        try {
409            mInstalld.createOatDir(oatDir, dexInstructionSet);
410        } catch (Exception e) {
411            throw InstallerException.from(e);
412        }
413    }
414
415    public void linkFile(String relativePath, String fromBase, String toBase)
416            throws InstallerException {
417        if (!checkBeforeRemote()) return;
418        try {
419            mInstalld.linkFile(relativePath, fromBase, toBase);
420        } catch (Exception e) {
421            throw InstallerException.from(e);
422        }
423    }
424
425    public void moveAb(String apkPath, String instructionSet, String outputPath)
426            throws InstallerException {
427        if (!checkBeforeRemote()) return;
428        try {
429            mInstalld.moveAb(apkPath, instructionSet, outputPath);
430        } catch (Exception e) {
431            throw InstallerException.from(e);
432        }
433    }
434
435    public void deleteOdex(String apkPath, String instructionSet, String outputPath)
436            throws InstallerException {
437        if (!checkBeforeRemote()) return;
438        try {
439            mInstalld.deleteOdex(apkPath, instructionSet, outputPath);
440        } catch (Exception e) {
441            throw InstallerException.from(e);
442        }
443    }
444
445    public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
446            String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException {
447        for (int i = 0; i < isas.length; i++) {
448            assertValidInstructionSet(isas[i]);
449        }
450        if (!checkBeforeRemote()) return false;
451        try {
452            return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas,
453                    volumeUuid, flags);
454        } catch (Exception e) {
455            throw InstallerException.from(e);
456        }
457    }
458
459    public void invalidateMounts() throws InstallerException {
460        if (!checkBeforeRemote()) return;
461        try {
462            mInstalld.invalidateMounts();
463        } catch (Exception e) {
464            throw InstallerException.from(e);
465        }
466    }
467
468    private static void assertValidInstructionSet(String instructionSet)
469            throws InstallerException {
470        for (String abi : Build.SUPPORTED_ABIS) {
471            if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) {
472                return;
473            }
474        }
475        throw new InstallerException("Invalid instruction set: " + instructionSet);
476    }
477
478    public static class InstallerException extends Exception {
479        public InstallerException(String detailMessage) {
480            super(detailMessage);
481        }
482
483        public static InstallerException from(Exception e) throws InstallerException {
484            throw new InstallerException(e.toString());
485        }
486    }
487}
488