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