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 static com.android.server.pm.DexOptHelper.useArtService;
20 
21 import android.annotation.AppIdInt;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.UserIdInt;
25 import android.content.Context;
26 import android.content.pm.PackageStats;
27 import android.os.Build;
28 import android.os.CreateAppDataArgs;
29 import android.os.CreateAppDataResult;
30 import android.os.IBinder;
31 import android.os.IInstalld;
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.Slog;
38 
39 import com.android.internal.os.BackgroundThread;
40 import com.android.server.SystemService;
41 
42 import dalvik.system.BlockGuard;
43 import dalvik.system.VMRuntime;
44 
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.List;
48 import java.util.concurrent.CompletableFuture;
49 import java.util.concurrent.CountDownLatch;
50 import java.util.concurrent.TimeUnit;
51 
52 public class Installer extends SystemService {
53     private static final String TAG = "Installer";
54 
55     /* ***************************************************************************
56      * IMPORTANT: These values are passed to native code. Keep them in sync with
57      * frameworks/native/cmds/installd/installd_constants.h
58      * **************************************************************************/
59     /** Application should be visible to everyone */
60     public static final int DEXOPT_PUBLIC         = 1 << 1;
61     /** Application wants to allow debugging of its code */
62     public static final int DEXOPT_DEBUGGABLE     = 1 << 2;
63     /** The system boot has finished */
64     public static final int DEXOPT_BOOTCOMPLETE   = 1 << 3;
65     /** Hint that the dexopt type is profile-guided. */
66     public static final int DEXOPT_PROFILE_GUIDED = 1 << 4;
67     /** The compilation is for a secondary dex file. */
68     public static final int DEXOPT_SECONDARY_DEX  = 1 << 5;
69     /** Ignore the result of dexoptNeeded and force compilation. */
70     public static final int DEXOPT_FORCE          = 1 << 6;
71     /** Indicates that the dex file passed to dexopt in on CE storage. */
72     public static final int DEXOPT_STORAGE_CE     = 1 << 7;
73     /** Indicates that the dex file passed to dexopt in on DE storage. */
74     public static final int DEXOPT_STORAGE_DE     = 1 << 8;
75     /** Indicates that dexopt is invoked from the background service. */
76     public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
77     /** Indicates that dexopt should restrict access to private APIs. */
78     public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10;
79     /** Indicates that dexopt should convert to CompactDex. */
80     public static final int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11;
81     /** Indicates that dexopt should generate an app image */
82     public static final int DEXOPT_GENERATE_APP_IMAGE = 1 << 12;
83     /** Indicates that dexopt may be run with different performance / priority tuned for restore */
84     public static final int DEXOPT_FOR_RESTORE = 1 << 13; // TODO(b/135202722): remove
85 
86     /** The result of the profile analysis indicating that the app should be optimized. */
87     public static final int PROFILE_ANALYSIS_OPTIMIZE = 1;
88     /** The result of the profile analysis indicating that the app should not be optimized. */
89     public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA = 2;
90     /**
91      * The result of the profile analysis indicating that the app should not be optimized because
92      * the profiles are empty.
93      */
94     public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3;
95 
96     /**
97      * The results of {@code getOdexVisibility}. See
98      * {@link #getOdexVisibility(String, String, String)} for details.
99      */
100     public static final int ODEX_NOT_FOUND = 0;
101     public static final int ODEX_IS_PUBLIC = 1;
102     public static final int ODEX_IS_PRIVATE = 2;
103 
104 
105     public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
106     public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
107     public static final int FLAG_STORAGE_EXTERNAL = IInstalld.FLAG_STORAGE_EXTERNAL;
108     public static final int FLAG_STORAGE_SDK = IInstalld.FLAG_STORAGE_SDK;
109 
110     public static final int FLAG_CLEAR_CACHE_ONLY = IInstalld.FLAG_CLEAR_CACHE_ONLY;
111     public static final int FLAG_CLEAR_CODE_CACHE_ONLY = IInstalld.FLAG_CLEAR_CODE_CACHE_ONLY;
112 
113     public static final int FLAG_FREE_CACHE_V2 = IInstalld.FLAG_FREE_CACHE_V2;
114     public static final int FLAG_FREE_CACHE_V2_DEFY_QUOTA = IInstalld.FLAG_FREE_CACHE_V2_DEFY_QUOTA;
115     public static final int FLAG_FREE_CACHE_NOOP = IInstalld.FLAG_FREE_CACHE_NOOP;
116     public static final int FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES =
117             IInstalld.FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES;
118 
119     public static final int FLAG_USE_QUOTA = IInstalld.FLAG_USE_QUOTA;
120     public static final int FLAG_FORCE = IInstalld.FLAG_FORCE;
121 
122     public static final int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES =
123             IInstalld.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
124 
125     private static final long CONNECT_RETRY_DELAY_MS = DateUtils.SECOND_IN_MILLIS;
126     private static final long CONNECT_WAIT_MS = 10 * DateUtils.SECOND_IN_MILLIS;
127 
128     private final boolean mIsolated;
129     private volatile boolean mDeferSetFirstBoot;
130     private volatile IInstalld mInstalld = null;
131     private volatile CountDownLatch mInstalldLatch = new CountDownLatch(1);
132     private volatile Object mWarnIfHeld;
133 
Installer(Context context)134     public Installer(Context context) {
135         this(context, false);
136     }
137 
138     /**
139      * @param isolated Make the installer isolated. See {@link isIsolated}.
140      */
Installer(Context context, boolean isolated)141     public Installer(Context context, boolean isolated) {
142         super(context);
143         mIsolated = isolated;
144     }
145 
146     /**
147      * Yell loudly if someone tries making future calls while holding a lock on
148      * the given object.
149      */
setWarnIfHeld(Object warnIfHeld)150     public void setWarnIfHeld(Object warnIfHeld) {
151         mWarnIfHeld = warnIfHeld;
152     }
153 
154     /**
155      * Returns true if the installer is isolated, i.e. if this object should <em>not</em> connect to
156      * the real {@code installd}. All remote calls will be ignored unless you extend this class and
157      * intercept them.
158      */
isIsolated()159     public boolean isIsolated() {
160         return mIsolated;
161     }
162 
163     @Override
onStart()164     public void onStart() {
165         if (mIsolated) {
166             mInstalld = null;
167             mInstalldLatch.countDown();
168         } else {
169             connect();
170         }
171     }
172 
connect()173     private void connect() {
174         IBinder binder = ServiceManager.getService("installd");
175         if (binder != null) {
176             try {
177                 binder.linkToDeath(() -> {
178                     Slog.w(TAG, "installd died; reconnecting");
179                     mInstalldLatch = new CountDownLatch(1);
180                     connect();
181                 }, 0);
182             } catch (RemoteException e) {
183                 binder = null;
184             }
185         }
186 
187         if (binder != null) {
188             IInstalld installd = IInstalld.Stub.asInterface(binder);
189             mInstalld = installd;
190             mInstalldLatch.countDown();
191             try {
192                 invalidateMounts();
193                 executeDeferredActions();
194             } catch (InstallerException ignored) {
195             }
196         } else {
197             Slog.w(TAG, "installd not found; trying again");
198             BackgroundThread.getHandler().postDelayed(this::connect, CONNECT_RETRY_DELAY_MS);
199         }
200     }
201 
202     /**
203      * Perform any deferred actions on mInstalld while the connection could not be made.
204      */
executeDeferredActions()205     private void executeDeferredActions() throws InstallerException {
206         if (mDeferSetFirstBoot) {
207             setFirstBoot();
208         }
209     }
210 
211     /**
212      * Do several pre-flight checks before making a remote call.
213      *
214      * @return if the remote call should continue.
215      */
checkBeforeRemote()216     private boolean checkBeforeRemote() throws InstallerException {
217         if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
218             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
219                     + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
220         }
221         if (mIsolated) {
222             Slog.i(TAG, "Ignoring request because this installer is isolated");
223             return false;
224         }
225 
226         try {
227             if (!mInstalldLatch.await(CONNECT_WAIT_MS, TimeUnit.MILLISECONDS)) {
228                 throw new InstallerException("time out waiting for the installer to be ready");
229             }
230         } catch (InterruptedException e) {
231             // Do nothing.
232         }
233 
234         return true;
235     }
236 
237     // We explicitly do NOT set previousAppId because the default value should always be 0.
238     // 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)239     static CreateAppDataArgs buildCreateAppDataArgs(String uuid, String packageName,
240             int userId, int flags, int appId, String seInfo, int targetSdkVersion,
241             boolean usesSdk) {
242         final CreateAppDataArgs args = new CreateAppDataArgs();
243         args.uuid = uuid;
244         args.packageName = packageName;
245         args.userId = userId;
246         args.flags = flags;
247         if (usesSdk) {
248             args.flags |= FLAG_STORAGE_SDK;
249         }
250         args.appId = appId;
251         args.seInfo = seInfo;
252         args.targetSdkVersion = targetSdkVersion;
253         return args;
254     }
255 
buildPlaceholderCreateAppDataResult()256     private static CreateAppDataResult buildPlaceholderCreateAppDataResult() {
257         final CreateAppDataResult result = new CreateAppDataResult();
258         result.ceDataInode = -1;
259         result.exceptionCode = 0;
260         result.exceptionMessage = null;
261         return result;
262     }
263 
buildReconcileSdkDataArgs(String uuid, String packageName, List<String> subDirNames, int userId, int appId, String seInfo, int flags)264     static ReconcileSdkDataArgs buildReconcileSdkDataArgs(String uuid, String packageName,
265             List<String> subDirNames, int userId, int appId,
266             String seInfo, int flags) {
267         final ReconcileSdkDataArgs args = new ReconcileSdkDataArgs();
268         args.uuid = uuid;
269         args.packageName = packageName;
270         args.subDirNames = subDirNames;
271         args.userId = userId;
272         args.appId = appId;
273         args.previousAppId = 0;
274         args.seInfo = seInfo;
275         args.flags = flags;
276         return args;
277     }
278 
createAppData(@onNull CreateAppDataArgs args)279     public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args)
280             throws InstallerException {
281         if (!checkBeforeRemote()) {
282             return buildPlaceholderCreateAppDataResult();
283         }
284         // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
285         args.previousAppId = 0;
286         try {
287             return mInstalld.createAppData(args);
288         } catch (Exception e) {
289             throw InstallerException.from(e);
290         }
291     }
292 
createAppDataBatched(@onNull CreateAppDataArgs[] args)293     public @NonNull CreateAppDataResult[] createAppDataBatched(@NonNull CreateAppDataArgs[] args)
294             throws InstallerException {
295         if (!checkBeforeRemote()) {
296             final CreateAppDataResult[] results = new CreateAppDataResult[args.length];
297             Arrays.fill(results, buildPlaceholderCreateAppDataResult());
298             return results;
299         }
300         // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
301         for (final CreateAppDataArgs arg : args) {
302             arg.previousAppId = 0;
303         }
304         try {
305             return mInstalld.createAppDataBatched(args);
306         } catch (Exception e) {
307             throw InstallerException.from(e);
308         }
309     }
310 
reconcileSdkData(@onNull ReconcileSdkDataArgs args)311     void reconcileSdkData(@NonNull ReconcileSdkDataArgs args)
312             throws InstallerException {
313         if (!checkBeforeRemote()) {
314             return;
315         }
316         try {
317             mInstalld.reconcileSdkData(args);
318         } catch (Exception e) {
319             throw InstallerException.from(e);
320         }
321     }
322 
323     /**
324      * Sets in Installd that it is first boot after data wipe
325      */
setFirstBoot()326     public void setFirstBoot() throws InstallerException {
327         if (!checkBeforeRemote()) {
328             return;
329         }
330         try {
331             // mInstalld might be null if the connection could not be established.
332             if (mInstalld != null) {
333                 mInstalld.setFirstBoot();
334             } else {
335                 // if it is null while trying to set the first boot, set a flag to try and set the
336                 // first boot when the connection is eventually established
337                 mDeferSetFirstBoot = true;
338             }
339         } catch (Exception e) {
340             throw InstallerException.from(e);
341         }
342     }
343 
344     /**
345      * Class that collects multiple {@code installd} operations together in an
346      * attempt to more efficiently execute them in bulk.
347      * <p>
348      * Instead of returning results immediately, {@link CompletableFuture}
349      * instances are returned which can be used to chain follow-up work for each
350      * request.
351      * <p>
352      * The creator of this object <em>must</em> invoke {@link #execute()}
353      * exactly once to begin execution of all pending operations. Once execution
354      * has been kicked off, no additional events can be enqueued into this
355      * instance, but multiple instances can safely exist in parallel.
356      */
357     public static class Batch {
358         private static final int CREATE_APP_DATA_BATCH_SIZE = 256;
359 
360         private boolean mExecuted;
361 
362         private final List<CreateAppDataArgs> mArgs = new ArrayList<>();
363         private final List<CompletableFuture<Long>> mFutures = new ArrayList<>();
364 
365         /**
366          * Enqueue the given {@code installd} operation to be executed in the
367          * future when {@link #execute(Installer)} is invoked.
368          * <p>
369          * Callers of this method are not required to hold a monitor lock on an
370          * {@link Installer} object.
371          */
372         @NonNull
createAppData(CreateAppDataArgs args)373         public synchronized CompletableFuture<Long> createAppData(CreateAppDataArgs args) {
374             if (mExecuted) {
375                 throw new IllegalStateException();
376             }
377             final CompletableFuture<Long> future = new CompletableFuture<>();
378             mArgs.add(args);
379             mFutures.add(future);
380             return future;
381         }
382 
383         /**
384          * Execute all pending {@code installd} operations that have been
385          * collected by this batch in a blocking fashion.
386          * <p>
387          * Callers of this method <em>must</em> hold a monitor lock on the given
388          * {@link Installer} object.
389          */
execute(@onNull Installer installer)390         public synchronized void execute(@NonNull Installer installer) throws InstallerException {
391             if (mExecuted) throw new IllegalStateException();
392             mExecuted = true;
393 
394             final int size = mArgs.size();
395             for (int i = 0; i < size; i += CREATE_APP_DATA_BATCH_SIZE) {
396                 final CreateAppDataArgs[] args = new CreateAppDataArgs[Math.min(size - i,
397                         CREATE_APP_DATA_BATCH_SIZE)];
398                 for (int j = 0; j < args.length; j++) {
399                     args[j] = mArgs.get(i + j);
400                 }
401                 final CreateAppDataResult[] results = installer.createAppDataBatched(args);
402                 for (int j = 0; j < args.length; j++) {
403                     final CreateAppDataResult result = results[j];
404                     final CompletableFuture<Long> future = mFutures.get(i + j);
405                     if (result.exceptionCode == 0) {
406                         future.complete(result.ceDataInode);
407                     } else {
408                         future.completeExceptionally(
409                                 new InstallerException(result.exceptionMessage));
410                     }
411                 }
412             }
413         }
414     }
415 
restoreconAppData(String uuid, String packageName, int userId, int flags, int appId, String seInfo)416     public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId,
417             String seInfo) throws InstallerException {
418         if (!checkBeforeRemote()) return;
419         try {
420             mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo);
421         } catch (Exception e) {
422             throw InstallerException.from(e);
423         }
424     }
425 
migrateAppData(String uuid, String packageName, int userId, int flags)426     public void migrateAppData(String uuid, String packageName, int userId, int flags)
427             throws InstallerException {
428         if (!checkBeforeRemote()) return;
429         try {
430             mInstalld.migrateAppData(uuid, packageName, userId, flags);
431         } catch (Exception e) {
432             throw InstallerException.from(e);
433         }
434     }
435 
clearAppData(String uuid, String packageName, int userId, int flags, long ceDataInode)436     public void clearAppData(String uuid, String packageName, int userId, int flags,
437             long ceDataInode) throws InstallerException {
438         if (!checkBeforeRemote()) return;
439         try {
440             mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode);
441         } catch (Exception e) {
442             throw InstallerException.from(e);
443         }
444     }
445 
destroyAppData(String uuid, String packageName, int userId, int flags, long ceDataInode)446     public void destroyAppData(String uuid, String packageName, int userId, int flags,
447             long ceDataInode) throws InstallerException {
448         if (!checkBeforeRemote()) return;
449         try {
450             mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode);
451         } catch (Exception e) {
452             throw InstallerException.from(e);
453         }
454     }
455 
fixupAppData(String uuid, int flags)456     public void fixupAppData(String uuid, int flags) throws InstallerException {
457         if (!checkBeforeRemote()) return;
458         try {
459             mInstalld.fixupAppData(uuid, flags);
460         } catch (Exception e) {
461             throw InstallerException.from(e);
462         }
463     }
464 
465     /**
466      * Remove all invalid dirs under app data folder.
467      * All dirs are supposed to be valid file and package names.
468      */
cleanupInvalidPackageDirs(String uuid, int userId, int flags)469     public void cleanupInvalidPackageDirs(String uuid, int userId, int flags)
470             throws InstallerException {
471         if (!checkBeforeRemote()) return;
472         try {
473             mInstalld.cleanupInvalidPackageDirs(uuid, userId, flags);
474         } catch (Exception e) {
475             throw InstallerException.from(e);
476         }
477     }
478 
moveCompleteApp(String fromUuid, String toUuid, String packageName, int appId, String seInfo, int targetSdkVersion, String fromCodePath)479     public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
480             int appId, String seInfo, int targetSdkVersion,
481             String fromCodePath) throws InstallerException {
482         if (!checkBeforeRemote()) return;
483         try {
484             mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, appId, seInfo,
485                     targetSdkVersion, fromCodePath);
486         } catch (Exception e) {
487             throw InstallerException.from(e);
488         }
489     }
490 
getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId, long[] ceDataInodes, String[] codePaths, PackageStats stats)491     public void getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId,
492             long[] ceDataInodes, String[] codePaths, PackageStats stats)
493             throws InstallerException {
494         if (!checkBeforeRemote()) return;
495         if (codePaths != null) {
496             for (String codePath : codePaths) {
497                 BlockGuard.getVmPolicy().onPathAccess(codePath);
498             }
499         }
500         try {
501             final long[] res = mInstalld.getAppSize(uuid, packageNames, userId, flags,
502                     appId, ceDataInodes, codePaths);
503             stats.codeSize += res[0];
504             stats.dataSize += res[1];
505             stats.cacheSize += res[2];
506             stats.externalCodeSize += res[3];
507             stats.externalDataSize += res[4];
508             stats.externalCacheSize += res[5];
509         } catch (Exception e) {
510             throw InstallerException.from(e);
511         }
512     }
513 
getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats)514     public void getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats)
515             throws InstallerException {
516         if (!checkBeforeRemote()) return;
517         try {
518             final long[] res = mInstalld.getUserSize(uuid, userId, flags, appIds);
519             stats.codeSize += res[0];
520             stats.dataSize += res[1];
521             stats.cacheSize += res[2];
522             stats.externalCodeSize += res[3];
523             stats.externalDataSize += res[4];
524             stats.externalCacheSize += res[5];
525         } catch (Exception e) {
526             throw InstallerException.from(e);
527         }
528     }
529 
getExternalSize(String uuid, int userId, int flags, int[] appIds)530     public long[] getExternalSize(String uuid, int userId, int flags, int[] appIds)
531             throws InstallerException {
532         if (!checkBeforeRemote()) return new long[6];
533         try {
534             return mInstalld.getExternalSize(uuid, userId, flags, appIds);
535         } catch (Exception e) {
536             throw InstallerException.from(e);
537         }
538     }
539 
540     /**
541      * To get all of the CrateMetadata of the crates for the specified user app by the installd.
542      *
543      * @param uuid the UUID
544      * @param packageNames the application package names
545      * @param userId the user id
546      * @return the array of CrateMetadata
547      */
548     @Nullable
getAppCrates(@onNull String uuid, @NonNull String[] packageNames, @UserIdInt int userId)549     public CrateMetadata[] getAppCrates(@NonNull String uuid, @NonNull String[] packageNames,
550             @UserIdInt int userId) throws InstallerException {
551         if (!checkBeforeRemote()) return null;
552         try {
553             return mInstalld.getAppCrates(uuid, packageNames, userId);
554         } catch (Exception e) {
555             throw InstallerException.from(e);
556         }
557     }
558 
559     /**
560      * To retrieve all of the CrateMetadata of the crate for the specified user app by the installd.
561      *
562      * @param uuid the UUID
563      * @param userId the user id
564      * @return the array of CrateMetadata
565      */
566     @Nullable
getUserCrates(String uuid, @UserIdInt int userId)567     public CrateMetadata[] getUserCrates(String uuid, @UserIdInt int userId)
568             throws InstallerException {
569         if (!checkBeforeRemote()) return null;
570         try {
571             return mInstalld.getUserCrates(uuid, userId);
572         } catch (Exception e) {
573             throw InstallerException.from(e);
574         }
575     }
576 
setAppQuota(String uuid, int userId, int appId, long cacheQuota)577     public void setAppQuota(String uuid, int userId, int appId, long cacheQuota)
578             throws InstallerException {
579         if (!checkBeforeRemote()) return;
580         try {
581             mInstalld.setAppQuota(uuid, userId, appId, cacheQuota);
582         } catch (Exception e) {
583             throw InstallerException.from(e);
584         }
585     }
586 
587     /**
588      * Runs dex optimization.
589      *
590      * @param apkPath Path of target APK
591      * @param uid UID of the package
592      * @param pkgName Name of the package
593      * @param instructionSet Target instruction set to run dex optimization.
594      * @param dexoptNeeded Necessary dex optimization for this request. Check
595      *        {@link dalvik.system.DexFile#NO_DEXOPT_NEEDED},
596      *        {@link dalvik.system.DexFile#DEX2OAT_FROM_SCRATCH},
597      *        {@link dalvik.system.DexFile#DEX2OAT_FOR_BOOT_IMAGE}, and
598      *        {@link dalvik.system.DexFile#DEX2OAT_FOR_FILTER}.
599      * @param outputPath Output path of generated dex optimization.
600      * @param dexFlags Check {@code DEXOPT_*} for allowed flags.
601      * @param compilerFilter Compiler filter like "verify", "speed-profile". Check
602      *                       {@code art/libartbase/base/compiler_filter.cc} for full list.
603      * @param volumeUuid UUID of the volume where the package data is stored. {@code null}
604      *                   represents internal storage.
605      * @param classLoaderContext This encodes the class loader chain (class loader type + class
606      *                           path) in a format compatible to dex2oat. Check
607      *                           {@code DexoptUtils.processContextForDexLoad} for further details.
608      * @param seInfo Selinux context to set for generated outputs.
609      * @param downgrade If set, allows downgrading {@code compilerFilter}. If downgrading is not
610      *                  allowed and requested {@code compilerFilter} is considered as downgrade,
611      *                  the request will be ignored.
612      * @param targetSdkVersion Target SDK version of the package.
613      * @param profileName Name of reference profile file.
614      * @param dexMetadataPath Specifies the location of dex metadata file.
615      * @param compilationReason Specifies the reason for the compilation like "install".
616      * @return {@code true} if {@code dexopt} is completed. {@code false} if it was cancelled.
617      *
618      * @throws InstallerException if {@code dexopt} fails.
619      */
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)620     public boolean dexopt(String apkPath, int uid, String pkgName, String instructionSet,
621             int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter,
622             @Nullable String volumeUuid, @Nullable String classLoaderContext,
623             @Nullable String seInfo, boolean downgrade, int targetSdkVersion,
624             @Nullable String profileName, @Nullable String dexMetadataPath,
625             @Nullable String compilationReason)
626             throws InstallerException, LegacyDexoptDisabledException {
627         checkLegacyDexoptDisabled();
628         assertValidInstructionSet(instructionSet);
629         BlockGuard.getVmPolicy().onPathAccess(apkPath);
630         BlockGuard.getVmPolicy().onPathAccess(outputPath);
631         BlockGuard.getVmPolicy().onPathAccess(dexMetadataPath);
632         if (!checkBeforeRemote()) return false;
633         try {
634             return mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
635                     dexFlags, compilerFilter, volumeUuid, classLoaderContext, seInfo, downgrade,
636                     targetSdkVersion, profileName, dexMetadataPath, compilationReason);
637         } catch (Exception e) {
638             throw InstallerException.from(e);
639         }
640     }
641 
642     /**
643      * Enables or disables dex optimization blocking.
644      *
645      * <p> Enabling blocking will also involve cancelling pending dexopt call and killing child
646      * processes forked from installd to run dexopt. The pending dexopt call will return false
647      * when it is cancelled.
648      *
649      * @param block set to true to enable blocking / false to disable blocking.
650      */
controlDexOptBlocking(boolean block)651     public void controlDexOptBlocking(boolean block) throws LegacyDexoptDisabledException {
652         checkLegacyDexoptDisabled();
653         try {
654             mInstalld.controlDexOptBlocking(block);
655         } catch (Exception e) {
656             Slog.w(TAG, "blockDexOpt failed", e);
657         }
658     }
659 
660     /**
661      * Analyzes the ART profiles of the given package, possibly merging the information
662      * into the reference profile. Returns whether or not we should optimize the package
663      * based on how much information is in the profile.
664      *
665      * @return one of {@link #PROFILE_ANALYSIS_OPTIMIZE},
666      *         {@link #PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA},
667      *         {@link #PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES}
668      */
mergeProfiles(int uid, String packageName, String profileName)669     public int mergeProfiles(int uid, String packageName, String profileName)
670             throws InstallerException, LegacyDexoptDisabledException {
671         checkLegacyDexoptDisabled();
672         if (!checkBeforeRemote()) return PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
673         try {
674             return mInstalld.mergeProfiles(uid, packageName, profileName);
675         } catch (Exception e) {
676             throw InstallerException.from(e);
677         }
678     }
679 
680     /**
681      * Dumps profiles associated with a package in a human readable format.
682      */
dumpProfiles(int uid, String packageName, String profileName, String codePath, boolean dumpClassesAndMethods)683     public boolean dumpProfiles(int uid, String packageName, String profileName, String codePath,
684             boolean dumpClassesAndMethods)
685             throws InstallerException, LegacyDexoptDisabledException {
686         checkLegacyDexoptDisabled();
687         if (!checkBeforeRemote()) return false;
688         BlockGuard.getVmPolicy().onPathAccess(codePath);
689         try {
690             return mInstalld.dumpProfiles(uid, packageName, profileName, codePath,
691                     dumpClassesAndMethods);
692         } catch (Exception e) {
693             throw InstallerException.from(e);
694         }
695     }
696 
copySystemProfile(String systemProfile, int uid, String packageName, String profileName)697     public boolean copySystemProfile(String systemProfile, int uid, String packageName,
698             String profileName) throws InstallerException, LegacyDexoptDisabledException {
699         checkLegacyDexoptDisabled();
700         if (!checkBeforeRemote()) return false;
701         try {
702             return mInstalld.copySystemProfile(systemProfile, uid, packageName, profileName);
703         } catch (Exception e) {
704             throw InstallerException.from(e);
705         }
706     }
707 
rmdex(String codePath, String instructionSet)708     public void rmdex(String codePath, String instructionSet)
709             throws InstallerException, LegacyDexoptDisabledException {
710         checkLegacyDexoptDisabled();
711         assertValidInstructionSet(instructionSet);
712         if (!checkBeforeRemote()) return;
713         BlockGuard.getVmPolicy().onPathAccess(codePath);
714         try {
715             mInstalld.rmdex(codePath, instructionSet);
716         } catch (Exception e) {
717             throw InstallerException.from(e);
718         }
719     }
720 
721     /**
722      * Remove a directory belonging to a package.
723      */
rmPackageDir(String packageName, String packageDir)724     public void rmPackageDir(String packageName, String packageDir) throws InstallerException {
725         if (!checkBeforeRemote()) return;
726         BlockGuard.getVmPolicy().onPathAccess(packageDir);
727         try {
728             mInstalld.rmPackageDir(packageName, packageDir);
729         } catch (Exception e) {
730             throw InstallerException.from(e);
731         }
732     }
733 
clearAppProfiles(String packageName, String profileName)734     public void clearAppProfiles(String packageName, String profileName)
735             throws InstallerException, LegacyDexoptDisabledException {
736         checkLegacyDexoptDisabled();
737         if (!checkBeforeRemote()) return;
738         try {
739             mInstalld.clearAppProfiles(packageName, profileName);
740         } catch (Exception e) {
741             throw InstallerException.from(e);
742         }
743     }
744 
destroyAppProfiles(String packageName)745     public void destroyAppProfiles(String packageName)
746             throws InstallerException, LegacyDexoptDisabledException {
747         checkLegacyDexoptDisabled();
748         if (!checkBeforeRemote()) return;
749         try {
750             mInstalld.destroyAppProfiles(packageName);
751         } catch (Exception e) {
752             throw InstallerException.from(e);
753         }
754     }
755 
756     /**
757      * Deletes the reference profile with the given name of the given package.
758      * @throws InstallerException if the deletion fails.
759      */
deleteReferenceProfile(String packageName, String profileName)760     public void deleteReferenceProfile(String packageName, String profileName)
761             throws InstallerException, LegacyDexoptDisabledException {
762         checkLegacyDexoptDisabled();
763         if (!checkBeforeRemote()) return;
764         try {
765             mInstalld.deleteReferenceProfile(packageName, profileName);
766         } catch (Exception e) {
767             throw InstallerException.from(e);
768         }
769     }
770 
createUserData(String uuid, int userId, int userSerial, int flags)771     public void createUserData(String uuid, int userId, int userSerial, int flags)
772             throws InstallerException {
773         if (!checkBeforeRemote()) return;
774         try {
775             mInstalld.createUserData(uuid, userId, userSerial, flags);
776         } catch (Exception e) {
777             throw InstallerException.from(e);
778         }
779     }
780 
destroyUserData(String uuid, int userId, int flags)781     public void destroyUserData(String uuid, int userId, int flags) throws InstallerException {
782         if (!checkBeforeRemote()) return;
783         try {
784             mInstalld.destroyUserData(uuid, userId, flags);
785         } catch (Exception e) {
786             throw InstallerException.from(e);
787         }
788     }
789 
790     /**
791      * Deletes cache from specified uuid until targetFreeBytes amount of space is free.
792      * flag denotes aggressive or non-aggresive mode where cache under quota is eligible or not
793      * respectively for clearing.
794      */
freeCache(String uuid, long targetFreeBytes, int flags)795     public void freeCache(String uuid, long targetFreeBytes, int flags) throws InstallerException {
796         if (!checkBeforeRemote()) return;
797         try {
798             mInstalld.freeCache(uuid, targetFreeBytes, flags);
799         } catch (Exception e) {
800             throw InstallerException.from(e);
801         }
802     }
803 
804     /**
805      * Links the 32 bit native library directory in an application's data
806      * directory to the real location for backward compatibility. Note that no
807      * such symlink is created for 64 bit shared libraries.
808      */
linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32, int userId)809     public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32,
810             int userId) throws InstallerException {
811         if (!checkBeforeRemote()) return;
812         BlockGuard.getVmPolicy().onPathAccess(nativeLibPath32);
813         try {
814             mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId);
815         } catch (Exception e) {
816             throw InstallerException.from(e);
817         }
818     }
819 
820     /**
821      * Creates an oat dir for given package and instruction set.
822      */
createOatDir(String packageName, String oatDir, String dexInstructionSet)823     public void createOatDir(String packageName, String oatDir, String dexInstructionSet)
824             throws InstallerException {
825         // This method should be allowed even if ART Service is enabled, because it's used for
826         // creating oat dirs before creating hard links for partial installation.
827         // TODO(b/274658735): Add an ART Service API to support hard linking.
828         if (!checkBeforeRemote()) return;
829         try {
830             mInstalld.createOatDir(packageName, oatDir, dexInstructionSet);
831         } catch (Exception e) {
832             throw InstallerException.from(e);
833         }
834     }
835 
836     /**
837      * Creates a hardlink for a path.
838      */
linkFile(String packageName, String relativePath, String fromBase, String toBase)839     public void linkFile(String packageName, String relativePath, String fromBase, String toBase)
840             throws InstallerException {
841         if (!checkBeforeRemote()) return;
842         BlockGuard.getVmPolicy().onPathAccess(fromBase);
843         BlockGuard.getVmPolicy().onPathAccess(toBase);
844         try {
845             mInstalld.linkFile(packageName, relativePath, fromBase, toBase);
846         } catch (Exception e) {
847             throw InstallerException.from(e);
848         }
849     }
850 
851     /**
852      * Moves oat/vdex/art from "B" set defined by ro.boot.slot_suffix to the default set.
853      */
moveAb(String packageName, String apkPath, String instructionSet, String outputPath)854     public void moveAb(String packageName, String apkPath, String instructionSet, String outputPath)
855             throws InstallerException {
856         if (!checkBeforeRemote()) return;
857         BlockGuard.getVmPolicy().onPathAccess(apkPath);
858         BlockGuard.getVmPolicy().onPathAccess(outputPath);
859         try {
860             mInstalld.moveAb(packageName, apkPath, instructionSet, outputPath);
861         } catch (Exception e) {
862             throw InstallerException.from(e);
863         }
864     }
865 
866     /**
867      * Deletes the optimized artifacts generated by ART and returns the number
868      * of freed bytes.
869      */
deleteOdex(String packageName, String apkPath, String instructionSet, String outputPath)870     public long deleteOdex(String packageName, String apkPath, String instructionSet,
871             String outputPath) throws InstallerException, LegacyDexoptDisabledException {
872         checkLegacyDexoptDisabled();
873         if (!checkBeforeRemote()) return -1;
874         BlockGuard.getVmPolicy().onPathAccess(apkPath);
875         BlockGuard.getVmPolicy().onPathAccess(outputPath);
876         try {
877             return mInstalld.deleteOdex(packageName, apkPath, instructionSet, outputPath);
878         } catch (Exception e) {
879             throw InstallerException.from(e);
880         }
881     }
882 
reconcileSecondaryDexFile(String apkPath, String packageName, int uid, String[] isas, @Nullable String volumeUuid, int flags)883     public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
884             String[] isas, @Nullable String volumeUuid, int flags)
885             throws InstallerException, LegacyDexoptDisabledException {
886         checkLegacyDexoptDisabled();
887         for (int i = 0; i < isas.length; i++) {
888             assertValidInstructionSet(isas[i]);
889         }
890         if (!checkBeforeRemote()) return false;
891         BlockGuard.getVmPolicy().onPathAccess(apkPath);
892         try {
893             return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas,
894                     volumeUuid, flags);
895         } catch (Exception e) {
896             throw InstallerException.from(e);
897         }
898     }
899 
hashSecondaryDexFile(String dexPath, String packageName, int uid, @Nullable String volumeUuid, int flags)900     public byte[] hashSecondaryDexFile(String dexPath, String packageName, int uid,
901             @Nullable String volumeUuid, int flags) throws InstallerException {
902         if (!checkBeforeRemote()) return new byte[0];
903         BlockGuard.getVmPolicy().onPathAccess(dexPath);
904         try {
905             return mInstalld.hashSecondaryDexFile(dexPath, packageName, uid, volumeUuid, flags);
906         } catch (Exception e) {
907             throw InstallerException.from(e);
908         }
909     }
910 
createProfileSnapshot(int appId, String packageName, String profileName, String classpath)911     public boolean createProfileSnapshot(int appId, String packageName, String profileName,
912             String classpath) throws InstallerException, LegacyDexoptDisabledException {
913         checkLegacyDexoptDisabled();
914         if (!checkBeforeRemote()) return false;
915         try {
916             return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath);
917         } catch (Exception e) {
918             throw InstallerException.from(e);
919         }
920     }
921 
destroyProfileSnapshot(String packageName, String profileName)922     public void destroyProfileSnapshot(String packageName, String profileName)
923             throws InstallerException, LegacyDexoptDisabledException {
924         checkLegacyDexoptDisabled();
925         if (!checkBeforeRemote()) return;
926         try {
927             mInstalld.destroyProfileSnapshot(packageName, profileName);
928         } catch (Exception e) {
929             throw InstallerException.from(e);
930         }
931     }
932 
invalidateMounts()933     public void invalidateMounts() throws InstallerException {
934         if (!checkBeforeRemote()) return;
935         try {
936             mInstalld.invalidateMounts();
937         } catch (Exception e) {
938             throw InstallerException.from(e);
939         }
940     }
941 
isQuotaSupported(String volumeUuid)942     public boolean isQuotaSupported(String volumeUuid) throws InstallerException {
943         if (!checkBeforeRemote()) return false;
944         try {
945             return mInstalld.isQuotaSupported(volumeUuid);
946         } catch (Exception e) {
947             throw InstallerException.from(e);
948         }
949     }
950 
951     /**
952      * Bind mount private volume CE and DE mirror storage.
953      */
tryMountDataMirror(String volumeUuid)954     public void tryMountDataMirror(String volumeUuid) throws InstallerException {
955         if (!checkBeforeRemote()) return;
956         try {
957             mInstalld.tryMountDataMirror(volumeUuid);
958         } catch (Exception e) {
959             throw InstallerException.from(e);
960         }
961     }
962 
963     /**
964      * Unmount private volume CE and DE mirror storage.
965      */
onPrivateVolumeRemoved(String volumeUuid)966     public void onPrivateVolumeRemoved(String volumeUuid) throws InstallerException {
967         if (!checkBeforeRemote()) return;
968         try {
969             mInstalld.onPrivateVolumeRemoved(volumeUuid);
970         } catch (Exception e) {
971             throw InstallerException.from(e);
972         }
973     }
974 
975     /**
976      * Prepares the app profile for the package at the given path:
977      * <ul>
978      *   <li>Creates the current profile for the given user ID, unless the user ID is
979      *     {@code UserHandle.USER_NULL}.</li>
980      *   <li>Merges the profile from the dex metadata file (if present) into the reference
981      *     profile.</li>
982      * </ul>
983      */
prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId, String profileName, String codePath, String dexMetadataPath)984     public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
985             String profileName, String codePath, String dexMetadataPath)
986             throws InstallerException, LegacyDexoptDisabledException {
987         checkLegacyDexoptDisabled();
988         if (!checkBeforeRemote()) return false;
989         BlockGuard.getVmPolicy().onPathAccess(codePath);
990         BlockGuard.getVmPolicy().onPathAccess(dexMetadataPath);
991         try {
992             return mInstalld.prepareAppProfile(pkg, userId, appId, profileName, codePath,
993                     dexMetadataPath);
994         } catch (Exception e) {
995             throw InstallerException.from(e);
996         }
997     }
998 
999     /**
1000      * Snapshots user data of the given package.
1001      *
1002      * @param pkg name of the package to snapshot user data for.
1003      * @param userId id of the user whose data to snapshot.
1004      * @param snapshotId id of this snapshot.
1005      * @param storageFlags flags controlling which data (CE or DE) to snapshot.
1006      *
1007      * @return {@code true} if the snapshot was taken successfully, or {@code false} if a remote
1008      * call shouldn't be continued. See {@link #checkBeforeRemote}.
1009      *
1010      * @throws InstallerException if failed to snapshot user data.
1011      */
snapshotAppData(String pkg, @UserIdInt int userId, int snapshotId, int storageFlags)1012     public boolean snapshotAppData(String pkg, @UserIdInt int userId, int snapshotId,
1013             int storageFlags) throws InstallerException {
1014         if (!checkBeforeRemote()) return false;
1015 
1016         try {
1017             mInstalld.snapshotAppData(null, pkg, userId, snapshotId, storageFlags);
1018             return true;
1019         } catch (Exception e) {
1020             throw InstallerException.from(e);
1021         }
1022     }
1023 
1024     /**
1025      * Restores user data snapshot of the given package.
1026      *
1027      * @param pkg name of the package to restore user data for.
1028      * @param appId id of the package to restore user data for.
1029      * @param userId id of the user whose data to restore.
1030      * @param snapshotId id of the snapshot to restore.
1031      * @param storageFlags flags controlling which data (CE or DE) to restore.
1032      *
1033      * @return {@code true} if user data restore was successful, or {@code false} if a remote call
1034      *  shouldn't be continued. See {@link #checkBeforeRemote}.
1035      *
1036      * @throws InstallerException if failed to restore user data.
1037      */
restoreAppDataSnapshot(String pkg, @AppIdInt int appId, String seInfo, @UserIdInt int userId, int snapshotId, int storageFlags)1038     public boolean restoreAppDataSnapshot(String pkg, @AppIdInt  int appId, String seInfo,
1039             @UserIdInt int userId, int snapshotId, int storageFlags) throws InstallerException {
1040         if (!checkBeforeRemote()) return false;
1041 
1042         try {
1043             mInstalld.restoreAppDataSnapshot(null, pkg, appId, seInfo, userId, snapshotId,
1044                     storageFlags);
1045             return true;
1046         } catch (Exception e) {
1047             throw InstallerException.from(e);
1048         }
1049     }
1050 
1051     /**
1052      * Deletes user data snapshot of the given package.
1053      *
1054      * @param pkg name of the package to delete user data snapshot for.
1055      * @param userId id of the user whose user data snapshot to delete.
1056      * @param snapshotId id of the snapshot to delete.
1057      * @param storageFlags flags controlling which user data snapshot (CE or DE) to delete.
1058      *
1059      * @return {@code true} if user data snapshot was successfully deleted, or {@code false} if a
1060      *  remote call shouldn't be continued. See {@link #checkBeforeRemote}.
1061      *
1062      * @throws InstallerException if failed to delete user data snapshot.
1063      */
destroyAppDataSnapshot(String pkg, @UserIdInt int userId, int snapshotId, int storageFlags)1064     public boolean destroyAppDataSnapshot(String pkg, @UserIdInt int userId,
1065             int snapshotId, int storageFlags) throws InstallerException {
1066         if (!checkBeforeRemote()) return false;
1067 
1068         try {
1069             mInstalld.destroyAppDataSnapshot(null, pkg, userId, 0, snapshotId, storageFlags);
1070             return true;
1071         } catch (Exception e) {
1072             throw InstallerException.from(e);
1073         }
1074     }
1075 
1076     /**
1077      * Deletes all snapshots of credential encrypted user data, where the snapshot id is not
1078      * included in {@code retainSnapshotIds}.
1079      *
1080      * @param userId id of the user whose user data snapshots to delete.
1081      * @param retainSnapshotIds ids of the snapshots that should not be deleted.
1082      *
1083      * @return {@code true} if the operation was successful, or {@code false} if a remote call
1084      * shouldn't be continued. See {@link #checkBeforeRemote}.
1085      *
1086      * @throws InstallerException if failed to delete user data snapshot.
1087      */
destroyCeSnapshotsNotSpecified(@serIdInt int userId, int[] retainSnapshotIds)1088     public boolean destroyCeSnapshotsNotSpecified(@UserIdInt int userId,
1089             int[] retainSnapshotIds) throws InstallerException {
1090         if (!checkBeforeRemote()) return false;
1091 
1092         try {
1093             mInstalld.destroyCeSnapshotsNotSpecified(null, userId, retainSnapshotIds);
1094             return true;
1095         } catch (Exception e) {
1096             throw InstallerException.from(e);
1097         }
1098     }
1099 
1100     /**
1101      * Migrates obb data from its legacy location {@code /data/media/obb} to
1102      * {@code /data/media/0/Android/obb}. This call is idempotent and a fast no-op if data has
1103      * already been migrated.
1104      *
1105      * @throws InstallerException if an error occurs.
1106      */
migrateLegacyObbData()1107     public boolean migrateLegacyObbData() throws InstallerException {
1108         if (!checkBeforeRemote()) return false;
1109 
1110         try {
1111             mInstalld.migrateLegacyObbData();
1112             return true;
1113         } catch (Exception e) {
1114             throw InstallerException.from(e);
1115         }
1116     }
1117 
assertValidInstructionSet(String instructionSet)1118     private static void assertValidInstructionSet(String instructionSet)
1119             throws InstallerException {
1120         for (String abi : Build.SUPPORTED_ABIS) {
1121             if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) {
1122                 return;
1123             }
1124         }
1125         throw new InstallerException("Invalid instruction set: " + instructionSet);
1126     }
1127 
compileLayouts(String apkPath, String packageName, String outDexFile, int uid)1128     public boolean compileLayouts(String apkPath, String packageName, String outDexFile, int uid) {
1129         try {
1130             return mInstalld.compileLayouts(apkPath, packageName, outDexFile, uid);
1131         } catch (RemoteException e) {
1132             return false;
1133         }
1134     }
1135 
1136     /**
1137      * Returns the visibility of the optimized artifacts.
1138      *
1139      * @param packageName name of the package.
1140      * @param apkPath path to the APK.
1141      * @param instructionSet instruction set of the optimized artifacts.
1142      * @param outputPath path to the directory that contains the optimized artifacts (i.e., the
1143      *   directory that {@link #dexopt} outputs to).
1144      *
1145      * @return {@link #ODEX_NOT_FOUND} if the optimized artifacts are not found, or
1146      *   {@link #ODEX_IS_PUBLIC} if the optimized artifacts are accessible by all apps, or
1147      *   {@link #ODEX_IS_PRIVATE} if the optimized artifacts are only accessible by this app.
1148      *
1149      * @throws InstallerException if failed to get the visibility of the optimized artifacts.
1150      */
getOdexVisibility(String packageName, String apkPath, String instructionSet, String outputPath)1151     public int getOdexVisibility(String packageName, String apkPath, String instructionSet,
1152             String outputPath) throws InstallerException, LegacyDexoptDisabledException {
1153         checkLegacyDexoptDisabled();
1154         if (!checkBeforeRemote()) return -1;
1155         BlockGuard.getVmPolicy().onPathAccess(apkPath);
1156         BlockGuard.getVmPolicy().onPathAccess(outputPath);
1157         try {
1158             return mInstalld.getOdexVisibility(packageName, apkPath, instructionSet, outputPath);
1159         } catch (Exception e) {
1160             throw InstallerException.from(e);
1161         }
1162     }
1163 
1164     public static class InstallerException extends Exception {
InstallerException(String detailMessage)1165         public InstallerException(String detailMessage) {
1166             super(detailMessage);
1167         }
1168 
from(Exception e)1169         public static InstallerException from(Exception e) throws InstallerException {
1170             throw new InstallerException(e.toString());
1171         }
1172     }
1173 
1174     /**
1175      * A checked exception that is thrown in legacy dexopt code paths when ART Service should be
1176      * used instead.
1177      */
1178     public static class LegacyDexoptDisabledException extends Exception {
1179         // TODO(b/260124949): Remove the legacy dexopt code paths, i.e. this exception and all code
1180         // that may throw it.
LegacyDexoptDisabledException()1181         public LegacyDexoptDisabledException() {
1182             super("Invalid call to legacy dexopt method while ART Service is in use.");
1183         }
1184     }
1185 
1186     /**
1187      * Throws LegacyDexoptDisabledException if ART Service should be used instead of the
1188      * {@link android.os.IInstalld} method that follows this method call.
1189      */
checkLegacyDexoptDisabled()1190     public static void checkLegacyDexoptDisabled() throws LegacyDexoptDisabledException {
1191         if (useArtService()) {
1192             throw new LegacyDexoptDisabledException();
1193         }
1194     }
1195 }
1196