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