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