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