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