Installer.java revision 019ac85ef5c79c21daa29f9805ee8f98462f0e05
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 final 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 InstallerConnection mInstaller;
62    private final IInstalld mInstalld;
63
64    private volatile Object mWarnIfHeld;
65
66    public Installer(Context context) {
67        super(context);
68        mInstaller = new InstallerConnection();
69        // TODO: reconnect if installd restarts
70        mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd"));
71    }
72
73    // Package-private installer that accepts a custom InstallerConnection. Used for
74    // OtaDexoptService.
75    Installer(Context context, InstallerConnection connection) {
76        super(context);
77        mInstaller = connection;
78        // TODO: reconnect if installd restarts
79        mInstalld = IInstalld.Stub.asInterface(ServiceManager.getService("installd"));
80    }
81
82    /**
83     * Yell loudly if someone tries making future calls while holding a lock on
84     * the given object.
85     */
86    public void setWarnIfHeld(Object warnIfHeld) {
87        mInstaller.setWarnIfHeld(warnIfHeld);
88        mWarnIfHeld = warnIfHeld;
89    }
90
91    @Override
92    public void onStart() {
93        Slog.i(TAG, "Waiting for installd to be ready.");
94        mInstaller.waitForConnection();
95    }
96
97    private void checkLock() {
98        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
99            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
100                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
101        }
102    }
103
104    public void createAppData(String uuid, String packageName, int userId, int flags, int appId,
105            String seInfo, int targetSdkVersion) throws InstallerException {
106        checkLock();
107        try {
108            mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
109                    targetSdkVersion);
110        } catch (RemoteException | ServiceSpecificException e) {
111            throw new InstallerException(e.getMessage());
112        }
113    }
114
115    public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId,
116            String seInfo) throws InstallerException {
117        checkLock();
118        try {
119            mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo);
120        } catch (RemoteException | ServiceSpecificException e) {
121            throw new InstallerException(e.getMessage());
122        }
123    }
124
125    public void migrateAppData(String uuid, String packageName, int userId, int flags)
126            throws InstallerException {
127        checkLock();
128        try {
129            mInstalld.migrateAppData(uuid, packageName, userId, flags);
130        } catch (RemoteException | ServiceSpecificException e) {
131            throw new InstallerException(e.getMessage());
132        }
133    }
134
135    public void clearAppData(String uuid, String packageName, int userId, int flags,
136            long ceDataInode) throws InstallerException {
137        checkLock();
138        try {
139            mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode);
140        } catch (RemoteException | ServiceSpecificException e) {
141            throw new InstallerException(e.getMessage());
142        }
143    }
144
145    public void destroyAppData(String uuid, String packageName, int userId, int flags,
146            long ceDataInode) throws InstallerException {
147        checkLock();
148        try {
149            mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode);
150        } catch (RemoteException | ServiceSpecificException e) {
151            throw new InstallerException(e.getMessage());
152        }
153    }
154
155    public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
156            String dataAppName, int appId, String seInfo, int targetSdkVersion)
157            throws InstallerException {
158        checkLock();
159        try {
160            mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo,
161                    targetSdkVersion);
162        } catch (RemoteException | ServiceSpecificException e) {
163            throw new InstallerException(e.getMessage());
164        }
165    }
166
167    public void getAppSize(String uuid, String pkgname, int userid, int flags, long ceDataInode,
168            String codePath, PackageStats stats) throws InstallerException {
169        final String[] res = mInstaller.execute("get_app_size", uuid, pkgname, userid, flags,
170                ceDataInode, codePath);
171        try {
172            stats.codeSize += Long.parseLong(res[1]);
173            stats.dataSize += Long.parseLong(res[2]);
174            stats.cacheSize += Long.parseLong(res[3]);
175        } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
176            throw new InstallerException("Invalid size result: " + Arrays.toString(res));
177        }
178    }
179
180    public long getAppDataInode(String uuid, String packageName, int userId, int flags)
181            throws InstallerException {
182        checkLock();
183        try {
184            return mInstalld.getAppDataInode(uuid, packageName, userId, flags);
185        } catch (RemoteException | ServiceSpecificException e) {
186            throw new InstallerException(e.getMessage());
187        }
188    }
189
190    public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
191            int dexFlags, String compilerFilter, String volumeUuid, String sharedLibraries)
192            throws InstallerException {
193        assertValidInstructionSet(instructionSet);
194        mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags,
195                compilerFilter, volumeUuid, sharedLibraries);
196    }
197
198    public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
199            int dexoptNeeded, @Nullable String outputPath, int dexFlags,
200            String compilerFilter, String volumeUuid, String sharedLibraries)
201            throws InstallerException {
202        assertValidInstructionSet(instructionSet);
203        mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
204                outputPath, dexFlags, compilerFilter, volumeUuid, sharedLibraries);
205    }
206
207    public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
208        return mInstaller.mergeProfiles(uid, pkgName);
209    }
210
211    public boolean dumpProfiles(String gid, String packageName, String codePaths)
212            throws InstallerException {
213        return mInstaller.dumpProfiles(gid, packageName, codePaths);
214    }
215
216    public void idmap(String targetApkPath, String overlayApkPath, int uid)
217            throws InstallerException {
218        mInstaller.execute("idmap", targetApkPath, overlayApkPath, uid);
219    }
220
221    public void rmdex(String codePath, String instructionSet) throws InstallerException {
222        assertValidInstructionSet(instructionSet);
223        mInstaller.execute("rmdex", codePath, instructionSet);
224    }
225
226    public void rmPackageDir(String packageDir) throws InstallerException {
227        mInstaller.execute("rmpackagedir", packageDir);
228    }
229
230    public void clearAppProfiles(String pkgName) throws InstallerException {
231        mInstaller.execute("clear_app_profiles", pkgName);
232    }
233
234    public void destroyAppProfiles(String pkgName) throws InstallerException {
235        mInstaller.execute("destroy_app_profiles", pkgName);
236    }
237
238    public void createUserData(String uuid, int userId, int userSerial, int flags)
239            throws InstallerException {
240        checkLock();
241        try {
242            mInstalld.createUserData(uuid, userId, userSerial, flags);
243        } catch (RemoteException | ServiceSpecificException e) {
244            throw new InstallerException(e.getMessage());
245        }
246    }
247
248    public void destroyUserData(String uuid, int userId, int flags) throws InstallerException {
249        checkLock();
250        try {
251            mInstalld.destroyUserData(uuid, userId, flags);
252        } catch (RemoteException | ServiceSpecificException e) {
253            throw new InstallerException(e.getMessage());
254        }
255    }
256
257    public void markBootComplete(String instructionSet) throws InstallerException {
258        assertValidInstructionSet(instructionSet);
259        mInstaller.execute("markbootcomplete", instructionSet);
260    }
261
262    public void freeCache(String uuid, long freeStorageSize) throws InstallerException {
263        mInstaller.execute("freecache", uuid, freeStorageSize);
264    }
265
266    /**
267     * Links the 32 bit native library directory in an application's data
268     * directory to the real location for backward compatibility. Note that no
269     * such symlink is created for 64 bit shared libraries.
270     */
271    public void linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
272            int userId) throws InstallerException {
273        mInstaller.execute("linklib", uuid, dataPath, nativeLibPath32, userId);
274    }
275
276    public void createOatDir(String oatDir, String dexInstructionSet)
277            throws InstallerException {
278        mInstaller.execute("createoatdir", oatDir, dexInstructionSet);
279    }
280
281    public void linkFile(String relativePath, String fromBase, String toBase)
282            throws InstallerException {
283        mInstaller.execute("linkfile", relativePath, fromBase, toBase);
284    }
285
286    public void moveAb(String apkPath, String instructionSet, String outputPath)
287            throws InstallerException {
288        mInstaller.execute("move_ab", apkPath, instructionSet, outputPath);
289    }
290
291    public void deleteOdex(String apkPath, String instructionSet, String outputPath)
292            throws InstallerException {
293        mInstaller.execute("delete_odex", apkPath, instructionSet, outputPath);
294    }
295
296    private static void assertValidInstructionSet(String instructionSet)
297            throws InstallerException {
298        for (String abi : Build.SUPPORTED_ABIS) {
299            if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) {
300                return;
301            }
302        }
303        throw new InstallerException("Invalid instruction set: " + instructionSet);
304    }
305}
306