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