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.CreateAppDataArgs;
27 import android.os.CreateAppDataResult;
28 import android.os.IBinder;
29 import android.os.IBinder.DeathRecipient;
30 import android.os.IInstalld;
31 import android.os.RemoteException;
32 import android.os.ServiceManager;
33 import android.os.storage.CrateMetadata;
34 import android.text.format.DateUtils;
35 import android.util.Slog;
36 
37 import com.android.internal.os.BackgroundThread;
38 import com.android.server.SystemService;
39 
40 import dalvik.system.BlockGuard;
41 import dalvik.system.VMRuntime;
42 
43 import java.io.FileDescriptor;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.List;
47 import java.util.concurrent.CompletableFuture;
48 
49 public class Installer extends SystemService {
50     private static final String TAG = "Installer";
51 
52     /* ***************************************************************************
53      * IMPORTANT: These values are passed to native code. Keep them in sync with
54      * frameworks/native/cmds/installd/installd_constants.h
55      * **************************************************************************/
56     /** Application should be visible to everyone */
57     public static final int DEXOPT_PUBLIC         = 1 << 1;
58     /** Application wants to allow debugging of its code */
59     public static final int DEXOPT_DEBUGGABLE     = 1 << 2;
60     /** The system boot has finished */
61     public static final int DEXOPT_BOOTCOMPLETE   = 1 << 3;
62     /** Hint that the dexopt type is profile-guided. */
63     public static final int DEXOPT_PROFILE_GUIDED = 1 << 4;
64     /** The compilation is for a secondary dex file. */
65     public static final int DEXOPT_SECONDARY_DEX  = 1 << 5;
66     /** Ignore the result of dexoptNeeded and force compilation. */
67     public static final int DEXOPT_FORCE          = 1 << 6;
68     /** Indicates that the dex file passed to dexopt in on CE storage. */
69     public static final int DEXOPT_STORAGE_CE     = 1 << 7;
70     /** Indicates that the dex file passed to dexopt in on DE storage. */
71     public static final int DEXOPT_STORAGE_DE     = 1 << 8;
72     /** Indicates that dexopt is invoked from the background service. */
73     public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
74     /** Indicates that dexopt should restrict access to private APIs. */
75     public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10;
76     /** Indicates that dexopt should convert to CompactDex. */
77     public static final int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11;
78     /** Indicates that dexopt should generate an app image */
79     public static final int DEXOPT_GENERATE_APP_IMAGE = 1 << 12;
80     /** Indicates that dexopt may be run with different performance / priority tuned for restore */
81     public static final int DEXOPT_FOR_RESTORE = 1 << 13; // TODO(b/135202722): remove
82 
83     /** The result of the profile analysis indicating that the app should be optimized. */
84     public static final int PROFILE_ANALYSIS_OPTIMIZE = 1;
85     /** The result of the profile analysis indicating that the app should not be optimized. */
86     public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA = 2;
87     /**
88      * The result of the profile analysis indicating that the app should not be optimized because
89      * the profiles are empty.
90      */
91     public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3;
92 
93 
94     public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
95     public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
96     public static final int FLAG_STORAGE_EXTERNAL = IInstalld.FLAG_STORAGE_EXTERNAL;
97 
98     public static final int FLAG_CLEAR_CACHE_ONLY = IInstalld.FLAG_CLEAR_CACHE_ONLY;
99     public static final int FLAG_CLEAR_CODE_CACHE_ONLY = IInstalld.FLAG_CLEAR_CODE_CACHE_ONLY;
100 
101     public static final int FLAG_FREE_CACHE_V2 = IInstalld.FLAG_FREE_CACHE_V2;
102     public static final int FLAG_FREE_CACHE_V2_DEFY_QUOTA = IInstalld.FLAG_FREE_CACHE_V2_DEFY_QUOTA;
103     public static final int FLAG_FREE_CACHE_NOOP = IInstalld.FLAG_FREE_CACHE_NOOP;
104 
105     public static final int FLAG_USE_QUOTA = IInstalld.FLAG_USE_QUOTA;
106     public static final int FLAG_FORCE = IInstalld.FLAG_FORCE;
107 
108     public static final int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES =
109             IInstalld.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
110 
111     private final boolean mIsolated;
112 
113     private volatile IInstalld mInstalld;
114     private volatile Object mWarnIfHeld;
115 
Installer(Context context)116     public Installer(Context context) {
117         this(context, false);
118     }
119 
120     /**
121      * @param isolated indicates if this object should <em>not</em> connect to
122      *            the real {@code installd}. All remote calls will be ignored
123      *            unless you extend this class and intercept them.
124      */
Installer(Context context, boolean isolated)125     public Installer(Context context, boolean isolated) {
126         super(context);
127         mIsolated = isolated;
128     }
129 
130     /**
131      * Yell loudly if someone tries making future calls while holding a lock on
132      * the given object.
133      */
setWarnIfHeld(Object warnIfHeld)134     public void setWarnIfHeld(Object warnIfHeld) {
135         mWarnIfHeld = warnIfHeld;
136     }
137 
138     @Override
onStart()139     public void onStart() {
140         if (mIsolated) {
141             mInstalld = null;
142         } else {
143             connect();
144         }
145     }
146 
connect()147     private void connect() {
148         IBinder binder = ServiceManager.getService("installd");
149         if (binder != null) {
150             try {
151                 binder.linkToDeath(new DeathRecipient() {
152                     @Override
153                     public void binderDied() {
154                         Slog.w(TAG, "installd died; reconnecting");
155                         connect();
156                     }
157                 }, 0);
158             } catch (RemoteException e) {
159                 binder = null;
160             }
161         }
162 
163         if (binder != null) {
164             mInstalld = IInstalld.Stub.asInterface(binder);
165             try {
166                 invalidateMounts();
167             } catch (InstallerException ignored) {
168             }
169         } else {
170             Slog.w(TAG, "installd not found; trying again");
171             BackgroundThread.getHandler().postDelayed(() -> {
172                 connect();
173             }, DateUtils.SECOND_IN_MILLIS);
174         }
175     }
176 
177     /**
178      * Do several pre-flight checks before making a remote call.
179      *
180      * @return if the remote call should continue.
181      */
checkBeforeRemote()182     private boolean checkBeforeRemote() {
183         if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
184             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
185                     + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
186         }
187         if (mIsolated) {
188             Slog.i(TAG, "Ignoring request because this installer is isolated");
189             return false;
190         } else {
191             return true;
192         }
193     }
194 
buildCreateAppDataArgs(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion)195     private static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName,
196             int userId, int flags, int appId, String seInfo, int targetSdkVersion) {
197         final CreateAppDataArgs args = new CreateAppDataArgs();
198         args.uuid = uuid;
199         args.packageName = packageName;
200         args.userId = userId;
201         args.flags = flags;
202         args.appId = appId;
203         args.seInfo = seInfo;
204         args.targetSdkVersion = targetSdkVersion;
205         return args;
206     }
207 
buildPlaceholderCreateAppDataResult()208     private static CreateAppDataResult buildPlaceholderCreateAppDataResult() {
209         final CreateAppDataResult result = new CreateAppDataResult();
210         result.ceDataInode = -1;
211         result.exceptionCode = 0;
212         result.exceptionMessage = null;
213         return result;
214     }
215 
216     /**
217      * @deprecated callers are encouraged to migrate to using {@link Batch} to
218      *             more efficiently handle operations in bulk.
219      */
220     @Deprecated
createAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion)221     public long createAppData(String uuid, String packageName, int userId, int flags, int appId,
222             String seInfo, int targetSdkVersion) throws InstallerException {
223         final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags,
224                 appId, seInfo, targetSdkVersion);
225         final CreateAppDataResult result = createAppData(args);
226         if (result.exceptionCode == 0) {
227             return result.ceDataInode;
228         } else {
229             throw new InstallerException(result.exceptionMessage);
230         }
231     }
232 
createAppData(@onNull CreateAppDataArgs args)233     public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args)
234             throws InstallerException {
235         if (!checkBeforeRemote()) {
236             return buildPlaceholderCreateAppDataResult();
237         }
238         try {
239             return mInstalld.createAppData(args);
240         } catch (Exception e) {
241             throw InstallerException.from(e);
242         }
243     }
244 
createAppDataBatched(@onNull CreateAppDataArgs[] args)245     public @NonNull CreateAppDataResult[] createAppDataBatched(@NonNull CreateAppDataArgs[] args)
246             throws InstallerException {
247         if (!checkBeforeRemote()) {
248             final CreateAppDataResult[] results = new CreateAppDataResult[args.length];
249             Arrays.fill(results, buildPlaceholderCreateAppDataResult());
250             return results;
251         }
252         try {
253             return mInstalld.createAppDataBatched(args);
254         } catch (Exception e) {
255             throw InstallerException.from(e);
256         }
257     }
258 
259     /**
260      * Class that collects multiple {@code installd} operations together in an
261      * attempt to more efficiently execute them in bulk.
262      * <p>
263      * Instead of returning results immediately, {@link CompletableFuture}
264      * instances are returned which can be used to chain follow-up work for each
265      * request.
266      * <p>
267      * The creator of this object <em>must</em> invoke {@link #execute()}
268      * exactly once to begin execution of all pending operations. Once execution
269      * has been kicked off, no additional events can be enqueued into this
270      * instance, but multiple instances can safely exist in parallel.
271      */
272     public static class Batch {
273         private static final int CREATE_APP_DATA_BATCH_SIZE = 256;
274 
275         private boolean mExecuted;
276 
277         private final List<CreateAppDataArgs> mArgs = new ArrayList<>();
278         private final List<CompletableFuture<Long>> mFutures = new ArrayList<>();
279 
280         /**
281          * Enqueue the given {@code installd} operation to be executed in the
282          * future when {@link #execute(Installer)} is invoked.
283          * <p>
284          * Callers of this method are not required to hold a monitor lock on an
285          * {@link Installer} object.
286          */
createAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo, int targetSdkVersion)287         public synchronized @NonNull CompletableFuture<Long> createAppData(String uuid,
288                 String packageName, int userId, int flags, int appId, String seInfo,
289                 int targetSdkVersion) {
290             if (mExecuted) throw new IllegalStateException();
291 
292             final CreateAppDataArgs args = buildCreateAppDataArgs(uuid, packageName, userId, flags,
293                     appId, seInfo, targetSdkVersion);
294             final CompletableFuture<Long> future = new CompletableFuture<>();
295             mArgs.add(args);
296             mFutures.add(future);
297             return future;
298         }
299 
300         /**
301          * Execute all pending {@code installd} operations that have been
302          * collected by this batch in a blocking fashion.
303          * <p>
304          * Callers of this method <em>must</em> hold a monitor lock on the given
305          * {@link Installer} object.
306          */
execute(@onNull Installer installer)307         public synchronized void execute(@NonNull Installer installer) throws InstallerException {
308             if (mExecuted) throw new IllegalStateException();
309             mExecuted = true;
310 
311             final int size = mArgs.size();
312             for (int i = 0; i < size; i += CREATE_APP_DATA_BATCH_SIZE) {
313                 final CreateAppDataArgs[] args = new CreateAppDataArgs[Math.min(size - i,
314                         CREATE_APP_DATA_BATCH_SIZE)];
315                 for (int j = 0; j < args.length; j++) {
316                     args[j] = mArgs.get(i + j);
317                 }
318                 final CreateAppDataResult[] results = installer.createAppDataBatched(args);
319                 for (int j = 0; j < args.length; j++) {
320                     final CreateAppDataResult result = results[j];
321                     final CompletableFuture<Long> future = mFutures.get(i + j);
322                     if (result.exceptionCode == 0) {
323                         future.complete(result.ceDataInode);
324                     } else {
325                         future.completeExceptionally(
326                                 new InstallerException(result.exceptionMessage));
327                     }
328                 }
329             }
330         }
331     }
332 
restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo)333     public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId,
334             String seInfo) throws InstallerException {
335         if (!checkBeforeRemote()) return;
336         try {
337             mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo);
338         } catch (Exception e) {
339             throw InstallerException.from(e);
340         }
341     }
342 
migrateAppData(String uuid, String packageName, int userId, int flags)343     public void migrateAppData(String uuid, String packageName, int userId, int flags)
344             throws InstallerException {
345         if (!checkBeforeRemote()) return;
346         try {
347             mInstalld.migrateAppData(uuid, packageName, userId, flags);
348         } catch (Exception e) {
349             throw InstallerException.from(e);
350         }
351     }
352 
clearAppData(String uuid, String packageName, int userId, int flags, long ceDataInode)353     public void clearAppData(String uuid, String packageName, int userId, int flags,
354             long ceDataInode) throws InstallerException {
355         if (!checkBeforeRemote()) return;
356         try {
357             mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode);
358         } catch (Exception e) {
359             throw InstallerException.from(e);
360         }
361     }
362 
destroyAppData(String uuid, String packageName, int userId, int flags, long ceDataInode)363     public void destroyAppData(String uuid, String packageName, int userId, int flags,
364             long ceDataInode) throws InstallerException {
365         if (!checkBeforeRemote()) return;
366         try {
367             mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode);
368         } catch (Exception e) {
369             throw InstallerException.from(e);
370         }
371     }
372 
fixupAppData(String uuid, int flags)373     public void fixupAppData(String uuid, int flags) throws InstallerException {
374         if (!checkBeforeRemote()) return;
375         try {
376             mInstalld.fixupAppData(uuid, flags);
377         } catch (Exception e) {
378             throw InstallerException.from(e);
379         }
380     }
381 
moveCompleteApp(String fromUuid, String toUuid, String packageName, int appId, String seInfo, int targetSdkVersion, String fromCodePath)382     public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
383             int appId, String seInfo, int targetSdkVersion,
384             String fromCodePath) throws InstallerException {
385         if (!checkBeforeRemote()) return;
386         try {
387             mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, appId, seInfo,
388                     targetSdkVersion, fromCodePath);
389         } catch (Exception e) {
390             throw InstallerException.from(e);
391         }
392     }
393 
getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId, long[] ceDataInodes, String[] codePaths, PackageStats stats)394     public void getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId,
395             long[] ceDataInodes, String[] codePaths, PackageStats stats)
396             throws InstallerException {
397         if (!checkBeforeRemote()) return;
398         if (codePaths != null) {
399             for (String codePath : codePaths) {
400                 BlockGuard.getVmPolicy().onPathAccess(codePath);
401             }
402         }
403         try {
404             final long[] res = mInstalld.getAppSize(uuid, packageNames, userId, flags,
405                     appId, ceDataInodes, codePaths);
406             stats.codeSize += res[0];
407             stats.dataSize += res[1];
408             stats.cacheSize += res[2];
409             stats.externalCodeSize += res[3];
410             stats.externalDataSize += res[4];
411             stats.externalCacheSize += res[5];
412         } catch (Exception e) {
413             throw InstallerException.from(e);
414         }
415     }
416 
getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats)417     public void getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats)
418             throws InstallerException {
419         if (!checkBeforeRemote()) return;
420         try {
421             final long[] res = mInstalld.getUserSize(uuid, userId, flags, appIds);
422             stats.codeSize += res[0];
423             stats.dataSize += res[1];
424             stats.cacheSize += res[2];
425             stats.externalCodeSize += res[3];
426             stats.externalDataSize += res[4];
427             stats.externalCacheSize += res[5];
428         } catch (Exception e) {
429             throw InstallerException.from(e);
430         }
431     }
432 
getExternalSize(String uuid, int userId, int flags, int[] appIds)433     public long[] getExternalSize(String uuid, int userId, int flags, int[] appIds)
434             throws InstallerException {
435         if (!checkBeforeRemote()) return new long[6];
436         try {
437             return mInstalld.getExternalSize(uuid, userId, flags, appIds);
438         } catch (Exception e) {
439             throw InstallerException.from(e);
440         }
441     }
442 
443     /**
444      * To get all of the CrateMetadata of the crates for the specified user app by the installd.
445      *
446      * @param uuid the UUID
447      * @param packageNames the application package names
448      * @param userId the user id
449      * @return the array of CrateMetadata
450      */
451     @Nullable
getAppCrates(@onNull String uuid, @NonNull String[] packageNames, @UserIdInt int userId)452     public CrateMetadata[] getAppCrates(@NonNull String uuid, @NonNull String[] packageNames,
453             @UserIdInt int userId) throws InstallerException {
454         if (!checkBeforeRemote()) return null;
455         try {
456             return mInstalld.getAppCrates(uuid, packageNames, userId);
457         } catch (Exception e) {
458             throw InstallerException.from(e);
459         }
460     }
461 
462     /**
463      * To retrieve all of the CrateMetadata of the crate for the specified user app by the installd.
464      *
465      * @param uuid the UUID
466      * @param userId the user id
467      * @return the array of CrateMetadata
468      */
469     @Nullable
getUserCrates(String uuid, @UserIdInt int userId)470     public CrateMetadata[] getUserCrates(String uuid, @UserIdInt int userId)
471             throws InstallerException {
472         if (!checkBeforeRemote()) return null;
473         try {
474             return mInstalld.getUserCrates(uuid, userId);
475         } catch (Exception e) {
476             throw InstallerException.from(e);
477         }
478     }
479 
setAppQuota(String uuid, int userId, int appId, long cacheQuota)480     public void setAppQuota(String uuid, int userId, int appId, long cacheQuota)
481             throws InstallerException {
482         if (!checkBeforeRemote()) return;
483         try {
484             mInstalld.setAppQuota(uuid, userId, appId, cacheQuota);
485         } catch (Exception e) {
486             throw InstallerException.from(e);
487         }
488     }
489 
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)490     public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
491             int dexoptNeeded, @Nullable String outputPath, int dexFlags,
492             String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
493             @Nullable String seInfo, boolean downgrade, int targetSdkVersion,
494             @Nullable String profileName, @Nullable String dexMetadataPath,
495             @Nullable String compilationReason) throws InstallerException {
496         assertValidInstructionSet(instructionSet);
497         BlockGuard.getVmPolicy().onPathAccess(apkPath);
498         BlockGuard.getVmPolicy().onPathAccess(outputPath);
499         BlockGuard.getVmPolicy().onPathAccess(dexMetadataPath);
500         if (!checkBeforeRemote()) return;
501         try {
502             mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
503                     dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
504                     targetSdkVersion, profileName, dexMetadataPath, compilationReason);
505         } catch (Exception e) {
506             throw InstallerException.from(e);
507         }
508     }
509 
510     /**
511      * Analyzes the ART profiles of the given package, possibly merging the information
512      * into the reference profile. Returns whether or not we should optimize the package
513      * based on how much information is in the profile.
514      *
515      * @return one of {@link #PROFILE_ANALYSIS_OPTIMIZE},
516      *         {@link #PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA},
517      *         {@link #PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES}
518      */
mergeProfiles(int uid, String packageName, String profileName)519     public int mergeProfiles(int uid, String packageName, String profileName)
520             throws InstallerException {
521         if (!checkBeforeRemote()) return PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
522         try {
523             return mInstalld.mergeProfiles(uid, packageName, profileName);
524         } catch (Exception e) {
525             throw InstallerException.from(e);
526         }
527     }
528 
dumpProfiles(int uid, String packageName, String profileName, String codePath)529     public boolean dumpProfiles(int uid, String packageName, String profileName, String codePath)
530             throws InstallerException {
531         if (!checkBeforeRemote()) return false;
532         BlockGuard.getVmPolicy().onPathAccess(codePath);
533         try {
534             return mInstalld.dumpProfiles(uid, packageName, profileName, codePath);
535         } catch (Exception e) {
536             throw InstallerException.from(e);
537         }
538     }
539 
copySystemProfile(String systemProfile, int uid, String packageName, String profileName)540     public boolean copySystemProfile(String systemProfile, int uid, String packageName,
541                 String profileName) throws InstallerException {
542         if (!checkBeforeRemote()) return false;
543         try {
544             return mInstalld.copySystemProfile(systemProfile, uid, packageName, profileName);
545         } catch (Exception e) {
546             throw InstallerException.from(e);
547         }
548     }
549 
rmdex(String codePath, String instructionSet)550     public void rmdex(String codePath, String instructionSet) throws InstallerException {
551         assertValidInstructionSet(instructionSet);
552         if (!checkBeforeRemote()) return;
553         BlockGuard.getVmPolicy().onPathAccess(codePath);
554         try {
555             mInstalld.rmdex(codePath, instructionSet);
556         } catch (Exception e) {
557             throw InstallerException.from(e);
558         }
559     }
560 
rmPackageDir(String packageDir)561     public void rmPackageDir(String packageDir) throws InstallerException {
562         if (!checkBeforeRemote()) return;
563         BlockGuard.getVmPolicy().onPathAccess(packageDir);
564         try {
565             mInstalld.rmPackageDir(packageDir);
566         } catch (Exception e) {
567             throw InstallerException.from(e);
568         }
569     }
570 
clearAppProfiles(String packageName, String profileName)571     public void clearAppProfiles(String packageName, String profileName) throws InstallerException {
572         if (!checkBeforeRemote()) return;
573         try {
574             mInstalld.clearAppProfiles(packageName, profileName);
575         } catch (Exception e) {
576             throw InstallerException.from(e);
577         }
578     }
579 
destroyAppProfiles(String packageName)580     public void destroyAppProfiles(String packageName) throws InstallerException {
581         if (!checkBeforeRemote()) return;
582         try {
583             mInstalld.destroyAppProfiles(packageName);
584         } catch (Exception e) {
585             throw InstallerException.from(e);
586         }
587     }
588 
createUserData(String uuid, int userId, int userSerial, int flags)589     public void createUserData(String uuid, int userId, int userSerial, int flags)
590             throws InstallerException {
591         if (!checkBeforeRemote()) return;
592         try {
593             mInstalld.createUserData(uuid, userId, userSerial, flags);
594         } catch (Exception e) {
595             throw InstallerException.from(e);
596         }
597     }
598 
destroyUserData(String uuid, int userId, int flags)599     public void destroyUserData(String uuid, int userId, int flags) throws InstallerException {
600         if (!checkBeforeRemote()) return;
601         try {
602             mInstalld.destroyUserData(uuid, userId, flags);
603         } catch (Exception e) {
604             throw InstallerException.from(e);
605         }
606     }
607 
freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags)608     public void freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags)
609             throws InstallerException {
610         if (!checkBeforeRemote()) return;
611         try {
612             mInstalld.freeCache(uuid, targetFreeBytes, cacheReservedBytes, flags);
613         } catch (Exception e) {
614             throw InstallerException.from(e);
615         }
616     }
617 
618     /**
619      * Links the 32 bit native library directory in an application's data
620      * directory to the real location for backward compatibility. Note that no
621      * such symlink is created for 64 bit shared libraries.
622      */
linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32, int userId)623     public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32,
624             int userId) throws InstallerException {
625         if (!checkBeforeRemote()) return;
626         BlockGuard.getVmPolicy().onPathAccess(nativeLibPath32);
627         try {
628             mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId);
629         } catch (Exception e) {
630             throw InstallerException.from(e);
631         }
632     }
633 
createOatDir(String oatDir, String dexInstructionSet)634     public void createOatDir(String oatDir, String dexInstructionSet)
635             throws InstallerException {
636         if (!checkBeforeRemote()) return;
637         try {
638             mInstalld.createOatDir(oatDir, dexInstructionSet);
639         } catch (Exception e) {
640             throw InstallerException.from(e);
641         }
642     }
643 
linkFile(String relativePath, String fromBase, String toBase)644     public void linkFile(String relativePath, String fromBase, String toBase)
645             throws InstallerException {
646         if (!checkBeforeRemote()) return;
647         BlockGuard.getVmPolicy().onPathAccess(fromBase);
648         BlockGuard.getVmPolicy().onPathAccess(toBase);
649         try {
650             mInstalld.linkFile(relativePath, fromBase, toBase);
651         } catch (Exception e) {
652             throw InstallerException.from(e);
653         }
654     }
655 
moveAb(String apkPath, String instructionSet, String outputPath)656     public void moveAb(String apkPath, String instructionSet, String outputPath)
657             throws InstallerException {
658         if (!checkBeforeRemote()) return;
659         BlockGuard.getVmPolicy().onPathAccess(apkPath);
660         BlockGuard.getVmPolicy().onPathAccess(outputPath);
661         try {
662             mInstalld.moveAb(apkPath, instructionSet, outputPath);
663         } catch (Exception e) {
664             throw InstallerException.from(e);
665         }
666     }
667 
668     /**
669      * Deletes the optimized artifacts generated by ART and returns the number
670      * of freed bytes.
671      */
deleteOdex(String apkPath, String instructionSet, String outputPath)672     public long deleteOdex(String apkPath, String instructionSet, String outputPath)
673             throws InstallerException {
674         if (!checkBeforeRemote()) return -1;
675         BlockGuard.getVmPolicy().onPathAccess(apkPath);
676         BlockGuard.getVmPolicy().onPathAccess(outputPath);
677         try {
678             return mInstalld.deleteOdex(apkPath, instructionSet, outputPath);
679         } catch (Exception e) {
680             throw InstallerException.from(e);
681         }
682     }
683 
installApkVerity(String filePath, FileDescriptor verityInput, int contentSize)684     public void installApkVerity(String filePath, FileDescriptor verityInput, int contentSize)
685             throws InstallerException {
686         if (!checkBeforeRemote()) return;
687         BlockGuard.getVmPolicy().onPathAccess(filePath);
688         try {
689             mInstalld.installApkVerity(filePath, verityInput, contentSize);
690         } catch (Exception e) {
691             throw InstallerException.from(e);
692         }
693     }
694 
assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash)695     public void assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash)
696             throws InstallerException {
697         if (!checkBeforeRemote()) return;
698         BlockGuard.getVmPolicy().onPathAccess(filePath);
699         try {
700             mInstalld.assertFsverityRootHashMatches(filePath, expectedHash);
701         } catch (Exception e) {
702             throw InstallerException.from(e);
703         }
704     }
705 
reconcileSecondaryDexFile(String apkPath, String packageName, int uid, String[] isas, @Nullable String volumeUuid, int flags)706     public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
707             String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException {
708         for (int i = 0; i < isas.length; i++) {
709             assertValidInstructionSet(isas[i]);
710         }
711         if (!checkBeforeRemote()) return false;
712         BlockGuard.getVmPolicy().onPathAccess(apkPath);
713         try {
714             return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas,
715                     volumeUuid, flags);
716         } catch (Exception e) {
717             throw InstallerException.from(e);
718         }
719     }
720 
hashSecondaryDexFile(String dexPath, String packageName, int uid, @Nullable String volumeUuid, int flags)721     public byte[] hashSecondaryDexFile(String dexPath, String packageName, int uid,
722             @Nullable String volumeUuid, int flags) throws InstallerException {
723         if (!checkBeforeRemote()) return new byte[0];
724         BlockGuard.getVmPolicy().onPathAccess(dexPath);
725         try {
726             return mInstalld.hashSecondaryDexFile(dexPath, packageName, uid, volumeUuid, flags);
727         } catch (Exception e) {
728             throw InstallerException.from(e);
729         }
730     }
731 
createProfileSnapshot(int appId, String packageName, String profileName, String classpath)732     public boolean createProfileSnapshot(int appId, String packageName, String profileName,
733             String classpath) throws InstallerException {
734         if (!checkBeforeRemote()) return false;
735         try {
736             return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath);
737         } catch (Exception e) {
738             throw InstallerException.from(e);
739         }
740     }
741 
destroyProfileSnapshot(String packageName, String profileName)742     public void destroyProfileSnapshot(String packageName, String profileName)
743             throws InstallerException {
744         if (!checkBeforeRemote()) return;
745         try {
746             mInstalld.destroyProfileSnapshot(packageName, profileName);
747         } catch (Exception e) {
748             throw InstallerException.from(e);
749         }
750     }
751 
invalidateMounts()752     public void invalidateMounts() throws InstallerException {
753         if (!checkBeforeRemote()) return;
754         try {
755             mInstalld.invalidateMounts();
756         } catch (Exception e) {
757             throw InstallerException.from(e);
758         }
759     }
760 
isQuotaSupported(String volumeUuid)761     public boolean isQuotaSupported(String volumeUuid) throws InstallerException {
762         if (!checkBeforeRemote()) return false;
763         try {
764             return mInstalld.isQuotaSupported(volumeUuid);
765         } catch (Exception e) {
766             throw InstallerException.from(e);
767         }
768     }
769 
770     /**
771      * Bind mount private volume CE and DE mirror storage.
772      */
tryMountDataMirror(String volumeUuid)773     public void tryMountDataMirror(String volumeUuid) throws InstallerException {
774         if (!checkBeforeRemote()) return;
775         try {
776             mInstalld.tryMountDataMirror(volumeUuid);
777         } catch (Exception e) {
778             throw InstallerException.from(e);
779         }
780     }
781 
782     /**
783      * Unmount private volume CE and DE mirror storage.
784      */
onPrivateVolumeRemoved(String volumeUuid)785     public void onPrivateVolumeRemoved(String volumeUuid) throws InstallerException {
786         if (!checkBeforeRemote()) return;
787         try {
788             mInstalld.onPrivateVolumeRemoved(volumeUuid);
789         } catch (Exception e) {
790             throw InstallerException.from(e);
791         }
792     }
793 
prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId, String profileName, String codePath, String dexMetadataPath)794     public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
795             String profileName, String codePath, String dexMetadataPath) throws InstallerException {
796         if (!checkBeforeRemote()) return false;
797         BlockGuard.getVmPolicy().onPathAccess(codePath);
798         BlockGuard.getVmPolicy().onPathAccess(dexMetadataPath);
799         try {
800             return mInstalld.prepareAppProfile(pkg, userId, appId, profileName, codePath,
801                     dexMetadataPath);
802         } catch (Exception e) {
803             throw InstallerException.from(e);
804         }
805     }
806 
807     /**
808      * Snapshots user data of the given package.
809      *
810      * @param pkg name of the package to snapshot user data for.
811      * @param userId id of the user whose data to snapshot.
812      * @param snapshotId id of this snapshot.
813      * @param storageFlags flags controlling which data (CE or DE) to snapshot.
814      *
815      * @return {@code true} if the snapshot was taken successfully, or {@code false} if a remote
816      * call shouldn't be continued. See {@link #checkBeforeRemote}.
817      *
818      * @throws InstallerException if failed to snapshot user data.
819      */
snapshotAppData(String pkg, @UserIdInt int userId, int snapshotId, int storageFlags)820     public boolean snapshotAppData(String pkg, @UserIdInt int userId, int snapshotId,
821             int storageFlags) throws InstallerException {
822         if (!checkBeforeRemote()) return false;
823 
824         try {
825             mInstalld.snapshotAppData(null, pkg, userId, snapshotId, storageFlags);
826             return true;
827         } catch (Exception e) {
828             throw InstallerException.from(e);
829         }
830     }
831 
832     /**
833      * Restores user data snapshot of the given package.
834      *
835      * @param pkg name of the package to restore user data for.
836      * @param appId id of the package to restore user data for.
837      * @param userId id of the user whose data to restore.
838      * @param snapshotId id of the snapshot to restore.
839      * @param storageFlags flags controlling which data (CE or DE) to restore.
840      *
841      * @return {@code true} if user data restore was successful, or {@code false} if a remote call
842      *  shouldn't be continued. See {@link #checkBeforeRemote}.
843      *
844      * @throws InstallerException if failed to restore user data.
845      */
restoreAppDataSnapshot(String pkg, @AppIdInt int appId, String seInfo, @UserIdInt int userId, int snapshotId, int storageFlags)846     public boolean restoreAppDataSnapshot(String pkg, @AppIdInt  int appId, String seInfo,
847             @UserIdInt int userId, int snapshotId, int storageFlags) throws InstallerException {
848         if (!checkBeforeRemote()) return false;
849 
850         try {
851             mInstalld.restoreAppDataSnapshot(null, pkg, appId, seInfo, userId, snapshotId,
852                     storageFlags);
853             return true;
854         } catch (Exception e) {
855             throw InstallerException.from(e);
856         }
857     }
858 
859     /**
860      * Deletes user data snapshot of the given package.
861      *
862      * @param pkg name of the package to delete user data snapshot for.
863      * @param userId id of the user whose user data snapshot to delete.
864      * @param snapshotId id of the snapshot to delete.
865      * @param storageFlags flags controlling which user data snapshot (CE or DE) to delete.
866      *
867      * @return {@code true} if user data snapshot was successfully deleted, or {@code false} if a
868      *  remote call shouldn't be continued. See {@link #checkBeforeRemote}.
869      *
870      * @throws InstallerException if failed to delete user data snapshot.
871      */
destroyAppDataSnapshot(String pkg, @UserIdInt int userId, int snapshotId, int storageFlags)872     public boolean destroyAppDataSnapshot(String pkg, @UserIdInt int userId,
873             int snapshotId, int storageFlags) throws InstallerException {
874         if (!checkBeforeRemote()) return false;
875 
876         try {
877             mInstalld.destroyAppDataSnapshot(null, pkg, userId, 0, snapshotId, storageFlags);
878             return true;
879         } catch (Exception e) {
880             throw InstallerException.from(e);
881         }
882     }
883 
884     /**
885      * Deletes all snapshots of credential encrypted user data, where the snapshot id is not
886      * included in {@code retainSnapshotIds}.
887      *
888      * @param userId id of the user whose user data snapshots to delete.
889      * @param retainSnapshotIds ids of the snapshots that should not be deleted.
890      *
891      * @return {@code true} if the operation was successful, or {@code false} if a remote call
892      * shouldn't be continued. See {@link #checkBeforeRemote}.
893      *
894      * @throws InstallerException if failed to delete user data snapshot.
895      */
destroyCeSnapshotsNotSpecified(@serIdInt int userId, int[] retainSnapshotIds)896     public boolean destroyCeSnapshotsNotSpecified(@UserIdInt int userId,
897             int[] retainSnapshotIds) throws InstallerException {
898         if (!checkBeforeRemote()) return false;
899 
900         try {
901             mInstalld.destroyCeSnapshotsNotSpecified(null, userId, retainSnapshotIds);
902             return true;
903         } catch (Exception e) {
904             throw InstallerException.from(e);
905         }
906     }
907 
908     /**
909      * Migrates obb data from its legacy location {@code /data/media/obb} to
910      * {@code /data/media/0/Android/obb}. This call is idempotent and a fast no-op if data has
911      * already been migrated.
912      *
913      * @throws InstallerException if an error occurs.
914      */
migrateLegacyObbData()915     public boolean migrateLegacyObbData() throws InstallerException {
916         if (!checkBeforeRemote()) return false;
917 
918         try {
919             mInstalld.migrateLegacyObbData();
920             return true;
921         } catch (Exception e) {
922             throw InstallerException.from(e);
923         }
924     }
925 
assertValidInstructionSet(String instructionSet)926     private static void assertValidInstructionSet(String instructionSet)
927             throws InstallerException {
928         for (String abi : Build.SUPPORTED_ABIS) {
929             if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) {
930                 return;
931             }
932         }
933         throw new InstallerException("Invalid instruction set: " + instructionSet);
934     }
935 
compileLayouts(String apkPath, String packageName, String outDexFile, int uid)936     public boolean compileLayouts(String apkPath, String packageName, String outDexFile, int uid) {
937         try {
938             return mInstalld.compileLayouts(apkPath, packageName, outDexFile, uid);
939         } catch (RemoteException e) {
940             return false;
941         }
942     }
943 
944     public static class InstallerException extends Exception {
InstallerException(String detailMessage)945         public InstallerException(String detailMessage) {
946             super(detailMessage);
947         }
948 
from(Exception e)949         public static InstallerException from(Exception e) throws InstallerException {
950             throw new InstallerException(e.toString());
951         }
952     }
953 }
954