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