Installer.java revision 464ed3d55f18b256ea1db78c9d46b08b54a96ce8
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 allow debugging of its code */
46    public static final int DEXOPT_DEBUGGABLE     = 1 << 2;
47    /** The system boot has finished */
48    public static final int DEXOPT_BOOTCOMPLETE   = 1 << 3;
49    /** Hint that the dexopt type is profile-guided. */
50    public static final int DEXOPT_PROFILE_GUIDED = 1 << 4;
51    /** The compilation is for a secondary dex file. */
52    public static final int DEXOPT_SECONDARY_DEX  = 1 << 5;
53    /** Ignore the result of dexoptNeeded and force compilation. */
54    public static final int DEXOPT_FORCE          = 1 << 6;
55    /** Indicates that the dex file passed to dexopt in on CE storage. */
56    public static final int DEXOPT_STORAGE_CE     = 1 << 7;
57    /** Indicates that the dex file passed to dexopt in on DE storage. */
58    public static final int DEXOPT_STORAGE_DE     = 1 << 8;
59    /** Indicates that dexopt is invoked from the background service. */
60    public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
61    /* Indicates that dexopt should not restrict access to private APIs.
62     * Must be kept in sync with com.android.internal.os.ZygoteInit. */
63    public static final int DEXOPT_DISABLE_HIDDEN_API_CHECKS = 1 << 10;
64
65    // NOTE: keep in sync with installd
66    public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
67    public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
68    public static final int FLAG_USE_QUOTA = 1 << 12;
69    public static final int FLAG_FREE_CACHE_V2 = 1 << 13;
70    public static final int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
71    public static final int FLAG_FREE_CACHE_NOOP = 1 << 15;
72    public static final int FLAG_FORCE = 1 << 16;
73
74    private final boolean mIsolated;
75
76    private volatile IInstalld mInstalld;
77    private volatile Object mWarnIfHeld;
78
79    public Installer(Context context) {
80        this(context, false);
81    }
82
83    /**
84     * @param isolated indicates if this object should <em>not</em> connect to
85     *            the real {@code installd}. All remote calls will be ignored
86     *            unless you extend this class and intercept them.
87     */
88    public Installer(Context context, boolean isolated) {
89        super(context);
90        mIsolated = isolated;
91    }
92
93    /**
94     * Yell loudly if someone tries making future calls while holding a lock on
95     * the given object.
96     */
97    public void setWarnIfHeld(Object warnIfHeld) {
98        mWarnIfHeld = warnIfHeld;
99    }
100
101    @Override
102    public void onStart() {
103        if (mIsolated) {
104            mInstalld = null;
105        } else {
106            connect();
107        }
108    }
109
110    private void connect() {
111        IBinder binder = ServiceManager.getService("installd");
112        if (binder != null) {
113            try {
114                binder.linkToDeath(new DeathRecipient() {
115                    @Override
116                    public void binderDied() {
117                        Slog.w(TAG, "installd died; reconnecting");
118                        connect();
119                    }
120                }, 0);
121            } catch (RemoteException e) {
122                binder = null;
123            }
124        }
125
126        if (binder != null) {
127            mInstalld = IInstalld.Stub.asInterface(binder);
128            try {
129                invalidateMounts();
130            } catch (InstallerException ignored) {
131            }
132        } else {
133            Slog.w(TAG, "installd not found; trying again");
134            BackgroundThread.getHandler().postDelayed(() -> {
135                connect();
136            }, DateUtils.SECOND_IN_MILLIS);
137        }
138    }
139
140    /**
141     * Do several pre-flight checks before making a remote call.
142     *
143     * @return if the remote call should continue.
144     */
145    private boolean checkBeforeRemote() {
146        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
147            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
148                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
149        }
150        if (mIsolated) {
151            Slog.i(TAG, "Ignoring request because this installer is isolated");
152            return false;
153        } else {
154            return true;
155        }
156    }
157
158    public long createAppData(String uuid, String packageName, int userId, int flags, int appId,
159            String seInfo, int targetSdkVersion) throws InstallerException {
160        if (!checkBeforeRemote()) return -1;
161        try {
162            return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
163                    targetSdkVersion);
164        } catch (Exception e) {
165            throw InstallerException.from(e);
166        }
167    }
168
169    public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId,
170            String seInfo) throws InstallerException {
171        if (!checkBeforeRemote()) return;
172        try {
173            mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo);
174        } catch (Exception e) {
175            throw InstallerException.from(e);
176        }
177    }
178
179    public void migrateAppData(String uuid, String packageName, int userId, int flags)
180            throws InstallerException {
181        if (!checkBeforeRemote()) return;
182        try {
183            mInstalld.migrateAppData(uuid, packageName, userId, flags);
184        } catch (Exception e) {
185            throw InstallerException.from(e);
186        }
187    }
188
189    public void clearAppData(String uuid, String packageName, int userId, int flags,
190            long ceDataInode) throws InstallerException {
191        if (!checkBeforeRemote()) return;
192        try {
193            mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode);
194        } catch (Exception e) {
195            throw InstallerException.from(e);
196        }
197    }
198
199    public void destroyAppData(String uuid, String packageName, int userId, int flags,
200            long ceDataInode) throws InstallerException {
201        if (!checkBeforeRemote()) return;
202        try {
203            mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode);
204        } catch (Exception e) {
205            throw InstallerException.from(e);
206        }
207    }
208
209    public void fixupAppData(String uuid, int flags) throws InstallerException {
210        if (!checkBeforeRemote()) return;
211        try {
212            mInstalld.fixupAppData(uuid, flags);
213        } catch (Exception e) {
214            throw InstallerException.from(e);
215        }
216    }
217
218    public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
219            String dataAppName, int appId, String seInfo, int targetSdkVersion)
220            throws InstallerException {
221        if (!checkBeforeRemote()) return;
222        try {
223            mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo,
224                    targetSdkVersion);
225        } catch (Exception e) {
226            throw InstallerException.from(e);
227        }
228    }
229
230    public void getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId,
231            long[] ceDataInodes, String[] codePaths, PackageStats stats)
232            throws InstallerException {
233        if (!checkBeforeRemote()) return;
234        try {
235            final long[] res = mInstalld.getAppSize(uuid, packageNames, userId, flags,
236                    appId, ceDataInodes, codePaths);
237            stats.codeSize += res[0];
238            stats.dataSize += res[1];
239            stats.cacheSize += res[2];
240            stats.externalCodeSize += res[3];
241            stats.externalDataSize += res[4];
242            stats.externalCacheSize += res[5];
243        } catch (Exception e) {
244            throw InstallerException.from(e);
245        }
246    }
247
248    public void getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats)
249            throws InstallerException {
250        if (!checkBeforeRemote()) return;
251        try {
252            final long[] res = mInstalld.getUserSize(uuid, userId, flags, appIds);
253            stats.codeSize += res[0];
254            stats.dataSize += res[1];
255            stats.cacheSize += res[2];
256            stats.externalCodeSize += res[3];
257            stats.externalDataSize += res[4];
258            stats.externalCacheSize += res[5];
259        } catch (Exception e) {
260            throw InstallerException.from(e);
261        }
262    }
263
264    public long[] getExternalSize(String uuid, int userId, int flags, int[] appIds)
265            throws InstallerException {
266        if (!checkBeforeRemote()) return new long[6];
267        try {
268            return mInstalld.getExternalSize(uuid, userId, flags, appIds);
269        } catch (Exception e) {
270            throw InstallerException.from(e);
271        }
272    }
273
274    public void setAppQuota(String uuid, int userId, int appId, long cacheQuota)
275            throws InstallerException {
276        if (!checkBeforeRemote()) return;
277        try {
278            mInstalld.setAppQuota(uuid, userId, appId, cacheQuota);
279        } catch (Exception e) {
280            throw InstallerException.from(e);
281        }
282    }
283
284    public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
285            int dexoptNeeded, @Nullable String outputPath, int dexFlags,
286            String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
287            @Nullable String seInfo, boolean downgrade, int targetSdkVersion)
288            throws InstallerException {
289        assertValidInstructionSet(instructionSet);
290        if (!checkBeforeRemote()) return;
291        try {
292            mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
293                    dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
294                    targetSdkVersion);
295        } catch (Exception e) {
296            throw InstallerException.from(e);
297        }
298    }
299
300    public boolean mergeProfiles(int uid, String packageName) throws InstallerException {
301        if (!checkBeforeRemote()) return false;
302        try {
303            return mInstalld.mergeProfiles(uid, packageName);
304        } catch (Exception e) {
305            throw InstallerException.from(e);
306        }
307    }
308
309    public boolean dumpProfiles(int uid, String packageName, String codePaths)
310            throws InstallerException {
311        if (!checkBeforeRemote()) return false;
312        try {
313            return mInstalld.dumpProfiles(uid, packageName, codePaths);
314        } catch (Exception e) {
315            throw InstallerException.from(e);
316        }
317    }
318
319    public boolean copySystemProfile(String systemProfile, int uid, String packageName)
320            throws InstallerException {
321        if (!checkBeforeRemote()) return false;
322        try {
323            return mInstalld.copySystemProfile(systemProfile, uid, packageName);
324        } catch (Exception e) {
325            throw InstallerException.from(e);
326        }
327    }
328
329    public void idmap(String targetApkPath, String overlayApkPath, int uid)
330            throws InstallerException {
331        if (!checkBeforeRemote()) return;
332        try {
333            mInstalld.idmap(targetApkPath, overlayApkPath, uid);
334        } catch (Exception e) {
335            throw InstallerException.from(e);
336        }
337    }
338
339    public void removeIdmap(String overlayApkPath) throws InstallerException {
340        if (!checkBeforeRemote()) return;
341        try {
342            mInstalld.removeIdmap(overlayApkPath);
343        } catch (Exception e) {
344            throw InstallerException.from(e);
345        }
346    }
347
348    public void rmdex(String codePath, String instructionSet) throws InstallerException {
349        assertValidInstructionSet(instructionSet);
350        if (!checkBeforeRemote()) return;
351        try {
352            mInstalld.rmdex(codePath, instructionSet);
353        } catch (Exception e) {
354            throw InstallerException.from(e);
355        }
356    }
357
358    public void rmPackageDir(String packageDir) throws InstallerException {
359        if (!checkBeforeRemote()) return;
360        try {
361            mInstalld.rmPackageDir(packageDir);
362        } catch (Exception e) {
363            throw InstallerException.from(e);
364        }
365    }
366
367    public void clearAppProfiles(String packageName) throws InstallerException {
368        if (!checkBeforeRemote()) return;
369        try {
370            mInstalld.clearAppProfiles(packageName);
371        } catch (Exception e) {
372            throw InstallerException.from(e);
373        }
374    }
375
376    public void destroyAppProfiles(String packageName) throws InstallerException {
377        if (!checkBeforeRemote()) return;
378        try {
379            mInstalld.destroyAppProfiles(packageName);
380        } catch (Exception e) {
381            throw InstallerException.from(e);
382        }
383    }
384
385    public void createUserData(String uuid, int userId, int userSerial, int flags)
386            throws InstallerException {
387        if (!checkBeforeRemote()) return;
388        try {
389            mInstalld.createUserData(uuid, userId, userSerial, flags);
390        } catch (Exception e) {
391            throw InstallerException.from(e);
392        }
393    }
394
395    public void destroyUserData(String uuid, int userId, int flags) throws InstallerException {
396        if (!checkBeforeRemote()) return;
397        try {
398            mInstalld.destroyUserData(uuid, userId, flags);
399        } catch (Exception e) {
400            throw InstallerException.from(e);
401        }
402    }
403
404    public void markBootComplete(String instructionSet) throws InstallerException {
405        assertValidInstructionSet(instructionSet);
406        if (!checkBeforeRemote()) return;
407        try {
408            mInstalld.markBootComplete(instructionSet);
409        } catch (Exception e) {
410            throw InstallerException.from(e);
411        }
412    }
413
414    public void freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags)
415            throws InstallerException {
416        if (!checkBeforeRemote()) return;
417        try {
418            mInstalld.freeCache(uuid, targetFreeBytes, cacheReservedBytes, flags);
419        } catch (Exception e) {
420            throw InstallerException.from(e);
421        }
422    }
423
424    /**
425     * Links the 32 bit native library directory in an application's data
426     * directory to the real location for backward compatibility. Note that no
427     * such symlink is created for 64 bit shared libraries.
428     */
429    public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32,
430            int userId) throws InstallerException {
431        if (!checkBeforeRemote()) return;
432        try {
433            mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId);
434        } catch (Exception e) {
435            throw InstallerException.from(e);
436        }
437    }
438
439    public void createOatDir(String oatDir, String dexInstructionSet)
440            throws InstallerException {
441        if (!checkBeforeRemote()) return;
442        try {
443            mInstalld.createOatDir(oatDir, dexInstructionSet);
444        } catch (Exception e) {
445            throw InstallerException.from(e);
446        }
447    }
448
449    public void linkFile(String relativePath, String fromBase, String toBase)
450            throws InstallerException {
451        if (!checkBeforeRemote()) return;
452        try {
453            mInstalld.linkFile(relativePath, fromBase, toBase);
454        } catch (Exception e) {
455            throw InstallerException.from(e);
456        }
457    }
458
459    public void moveAb(String apkPath, String instructionSet, String outputPath)
460            throws InstallerException {
461        if (!checkBeforeRemote()) return;
462        try {
463            mInstalld.moveAb(apkPath, instructionSet, outputPath);
464        } catch (Exception e) {
465            throw InstallerException.from(e);
466        }
467    }
468
469    public void deleteOdex(String apkPath, String instructionSet, String outputPath)
470            throws InstallerException {
471        if (!checkBeforeRemote()) return;
472        try {
473            mInstalld.deleteOdex(apkPath, instructionSet, outputPath);
474        } catch (Exception e) {
475            throw InstallerException.from(e);
476        }
477    }
478
479    public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
480            String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException {
481        for (int i = 0; i < isas.length; i++) {
482            assertValidInstructionSet(isas[i]);
483        }
484        if (!checkBeforeRemote()) return false;
485        try {
486            return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas,
487                    volumeUuid, flags);
488        } catch (Exception e) {
489            throw InstallerException.from(e);
490        }
491    }
492
493    public byte[] hashSecondaryDexFile(String dexPath, String packageName, int uid,
494            @Nullable String volumeUuid, int flags) throws InstallerException {
495        if (!checkBeforeRemote()) return new byte[0];
496        try {
497            return mInstalld.hashSecondaryDexFile(dexPath, packageName, uid, volumeUuid, flags);
498        } catch (Exception e) {
499            throw InstallerException.from(e);
500        }
501    }
502
503    public boolean createProfileSnapshot(int appId, String packageName, String codePath)
504            throws InstallerException {
505        if (!checkBeforeRemote()) return false;
506        try {
507            return mInstalld.createProfileSnapshot(appId, packageName, codePath);
508        } catch (Exception e) {
509            throw InstallerException.from(e);
510        }
511    }
512
513    public void destroyProfileSnapshot(String packageName, String codePath)
514            throws InstallerException {
515        if (!checkBeforeRemote()) return;
516        try {
517            mInstalld.destroyProfileSnapshot(packageName, codePath);
518        } catch (Exception e) {
519            throw InstallerException.from(e);
520        }
521    }
522
523    public void invalidateMounts() throws InstallerException {
524        if (!checkBeforeRemote()) return;
525        try {
526            mInstalld.invalidateMounts();
527        } catch (Exception e) {
528            throw InstallerException.from(e);
529        }
530    }
531
532    public boolean isQuotaSupported(String volumeUuid) throws InstallerException {
533        if (!checkBeforeRemote()) return false;
534        try {
535            return mInstalld.isQuotaSupported(volumeUuid);
536        } catch (Exception e) {
537            throw InstallerException.from(e);
538        }
539    }
540
541    private static void assertValidInstructionSet(String instructionSet)
542            throws InstallerException {
543        for (String abi : Build.SUPPORTED_ABIS) {
544            if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) {
545                return;
546            }
547        }
548        throw new InstallerException("Invalid instruction set: " + instructionSet);
549    }
550
551    public static class InstallerException extends Exception {
552        public InstallerException(String detailMessage) {
553            super(detailMessage);
554        }
555
556        public static InstallerException from(Exception e) throws InstallerException {
557            throw new InstallerException(e.toString());
558        }
559    }
560}
561