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