• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.apex.ApexInfo;
25 import android.apex.ApexInfoList;
26 import android.apex.ApexSessionInfo;
27 import android.apex.ApexSessionParams;
28 import android.apex.CompressedApexInfoList;
29 import android.apex.IApexService;
30 import android.content.pm.ApplicationInfo;
31 import android.content.pm.PackageInfo;
32 import android.content.pm.PackageManager;
33 import android.content.pm.SigningDetails;
34 import android.content.pm.parsing.result.ParseResult;
35 import android.content.pm.parsing.result.ParseTypeImpl;
36 import android.os.Binder;
37 import android.os.Environment;
38 import android.os.RemoteException;
39 import android.os.ServiceManager;
40 import android.os.Trace;
41 import android.sysprop.ApexProperties;
42 import android.text.TextUtils;
43 import android.util.ArrayMap;
44 import android.util.ArraySet;
45 import android.util.PrintWriterPrinter;
46 import android.util.Singleton;
47 import android.util.Slog;
48 import android.util.SparseArray;
49 import android.util.apk.ApkSignatureVerifier;
50 
51 import com.android.internal.annotations.GuardedBy;
52 import com.android.internal.annotations.VisibleForTesting;
53 import com.android.internal.util.IndentingPrintWriter;
54 import com.android.internal.util.Preconditions;
55 import com.android.modules.utils.build.UnboundedSdkLevel;
56 import com.android.server.pm.parsing.PackageParser2;
57 import com.android.server.pm.parsing.pkg.AndroidPackage;
58 import com.android.server.pm.parsing.pkg.ParsedPackage;
59 import com.android.server.pm.pkg.component.ParsedApexSystemService;
60 import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
61 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
62 import com.android.server.utils.TimingsTraceAndSlog;
63 
64 import com.google.android.collect.Lists;
65 
66 import java.io.File;
67 import java.io.PrintWriter;
68 import java.lang.annotation.Retention;
69 import java.lang.annotation.RetentionPolicy;
70 import java.nio.file.Path;
71 import java.util.ArrayList;
72 import java.util.Collections;
73 import java.util.HashSet;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.Objects;
77 import java.util.Set;
78 import java.util.concurrent.ExecutorService;
79 
80 /**
81  * ApexManager class handles communications with the apex service to perform operation and queries,
82  * as well as providing caching to avoid unnecessary calls to the service.
83  */
84 public abstract class ApexManager {
85 
86     private static final String TAG = "ApexManager";
87 
88     public static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
89     static final int MATCH_FACTORY_PACKAGE = 1 << 1;
90 
91     private static final String VNDK_APEX_MODULE_NAME_PREFIX = "com.android.vndk.";
92 
93     private static final Singleton<ApexManager> sApexManagerSingleton =
94             new Singleton<ApexManager>() {
95                 @Override
96                 protected ApexManager create() {
97                     if (ApexProperties.updatable().orElse(false)) {
98                         return new ApexManagerImpl();
99                     } else {
100                         return new ApexManagerFlattenedApex();
101                     }
102                 }
103             };
104 
105     /**
106      * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex}
107      * depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()}
108      * evaluates to {@code true}.
109      * @hide
110      */
getInstance()111     public static ApexManager getInstance() {
112         return sApexManagerSingleton.get();
113     }
114 
115     /**
116      * Minimal information about APEX mount points and the original APEX package they refer to.
117      * @hide
118      */
119     public static class ActiveApexInfo {
120         @Nullable public final String apexModuleName;
121         public final File apexDirectory;
122         public final File preInstalledApexPath;
123         public final File apexFile;
124         public final boolean activeApexChanged;
125 
ActiveApexInfo(File apexDirectory, File preInstalledApexPath, File apexFile)126         private ActiveApexInfo(File apexDirectory, File preInstalledApexPath, File apexFile) {
127             this(null, apexDirectory, preInstalledApexPath, apexFile, false);
128         }
129 
ActiveApexInfo(@ullable String apexModuleName, File apexDirectory, File preInstalledApexPath, File apexFile, boolean activeApexChanged)130         private ActiveApexInfo(@Nullable String apexModuleName, File apexDirectory,
131                 File preInstalledApexPath, File apexFile, boolean activeApexChanged) {
132             this.apexModuleName = apexModuleName;
133             this.apexDirectory = apexDirectory;
134             this.preInstalledApexPath = preInstalledApexPath;
135             this.apexFile = apexFile;
136             this.activeApexChanged = activeApexChanged;
137         }
138 
ActiveApexInfo(ApexInfo apexInfo)139         private ActiveApexInfo(ApexInfo apexInfo) {
140             this(
141                     apexInfo.moduleName,
142                     new File(Environment.getApexDirectory() + File.separator
143                             + apexInfo.moduleName),
144                     new File(apexInfo.preinstalledModulePath),
145                     new File(apexInfo.modulePath),
146                     apexInfo.activeApexChanged);
147         }
148     }
149 
150     /**
151      * Returns {@link ActiveApexInfo} records relative to all active APEX packages.
152      *
153      * @hide
154      */
getActiveApexInfos()155     public abstract List<ActiveApexInfo> getActiveApexInfos();
156 
157     /**
158      * Called by package manager service to scan apex package files when device boots up.
159      *
160      * @param packageParser The package parser to support apex package parsing and caching parsed
161      *                      results.
162      * @param executorService An executor to support parallel package parsing.
163      */
scanApexPackagesTraced(@onNull PackageParser2 packageParser, @NonNull ExecutorService executorService)164     abstract void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
165             @NonNull ExecutorService executorService);
166 
167     /**
168      * Retrieves information about an APEX package.
169      *
170      * @param packageName the package name to look for. Note that this is the package name reported
171      *                    in the APK container manifest (i.e. AndroidManifest.xml), which might
172      *                    differ from the one reported in the APEX manifest (i.e.
173      *                    apex_manifest.json).
174      * @param flags the type of package to return. This may match to active packages
175      *              and factory (pre-installed) packages.
176      * @return a PackageInfo object with the information about the package, or null if the package
177      *         is not found.
178      */
179     @Nullable
getPackageInfo(String packageName, @PackageInfoFlags int flags)180     public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
181 
182     /**
183      * Retrieves information about all active APEX packages.
184      *
185      * @return a List of PackageInfo object, each one containing information about a different
186      *         active package.
187      */
getActivePackages()188     abstract List<PackageInfo> getActivePackages();
189 
190     /**
191      * Retrieves information about all active pre-installed APEX packages.
192      *
193      * @return a List of PackageInfo object, each one containing information about a different
194      *         active pre-installed package.
195      */
getFactoryPackages()196     abstract List<PackageInfo> getFactoryPackages();
197 
198     /**
199      * Retrieves information about all inactive APEX packages.
200      *
201      * @return a List of PackageInfo object, each one containing information about a different
202      *         inactive package.
203      */
getInactivePackages()204     abstract List<PackageInfo> getInactivePackages();
205 
206     /**
207      * Checks if {@code packageName} is an apex package.
208      *
209      * @param packageName package to check.
210      * @return {@code true} if {@code packageName} is an apex package.
211      */
isApexPackage(String packageName)212     abstract boolean isApexPackage(String packageName);
213 
214     /**
215      * Whether the APEX package is pre-installed or not.
216      *
217      * @param packageInfo the package to check
218      * @return {@code true} if this package is pre-installed, {@code false} otherwise.
219      */
isFactory(@onNull PackageInfo packageInfo)220     public static boolean isFactory(@NonNull PackageInfo packageInfo) {
221         return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
222     }
223 
224     /**
225      * Returns the active apex package's name that contains the (apk) package.
226      *
227      * @param containedPackageName The (apk) package that might be in a apex
228      * @return the apex package's name of {@code null} if the {@code containedPackage} is not inside
229      *         any apex.
230      */
231     @Nullable
getActiveApexPackageNameContainingPackage( @onNull String containedPackageName)232     public abstract String getActiveApexPackageNameContainingPackage(
233             @NonNull String containedPackageName);
234 
235     /**
236      * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
237      * track the different states of a session.
238      *
239      * @param sessionId the identifier of the session.
240      * @return an ApexSessionInfo object, or null if the session is not known.
241      */
242     @Nullable
getStagedSessionInfo(int sessionId)243     abstract ApexSessionInfo getStagedSessionInfo(int sessionId);
244 
245     /**
246      * Returns array of all staged sessions known to apexd.
247      */
248     @NonNull
getSessions()249     abstract SparseArray<ApexSessionInfo> getSessions();
250 
251     /**
252      * Submit a staged session to apex service. This causes the apex service to perform some initial
253      * verification and accept or reject the session. Submitting a session successfully is not
254      * enough for it to be activated at the next boot, the caller needs to call
255      * {@link #markStagedSessionReady(int)}.
256      *
257      * @throws PackageManagerException if call to apexd fails
258      */
submitStagedSession(ApexSessionParams params)259     abstract ApexInfoList submitStagedSession(ApexSessionParams params)
260             throws PackageManagerException;
261 
262     /**
263      * Returns {@code ApeInfo} about apex sessions that have been marked ready via
264      * {@link #markStagedSessionReady(int)}
265      *
266      * Returns empty array if there is no staged apex session or if there is any error.
267      */
getStagedApexInfos(ApexSessionParams params)268     abstract ApexInfo[] getStagedApexInfos(ApexSessionParams params);
269 
270     /**
271      * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
272      * applied at next reboot.
273      *
274      * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
275      * @throws PackageManagerException if call to apexd fails
276      */
markStagedSessionReady(int sessionId)277     abstract void markStagedSessionReady(int sessionId) throws PackageManagerException;
278 
279     /**
280      * Marks a staged session as successful.
281      *
282      * <p>Only activated session can be marked as successful.
283      *
284      * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
285      *                  successful.
286      */
markStagedSessionSuccessful(int sessionId)287     abstract void markStagedSessionSuccessful(int sessionId);
288 
289     /**
290      * Whether the current device supports the management of APEX packages.
291      *
292      * @return true if APEX packages can be managed on this device, false otherwise.
293      */
isApexSupported()294     abstract boolean isApexSupported();
295 
296     /**
297      * Abandons the (only) active session previously submitted.
298      *
299      * @return {@code true} upon success, {@code false} if any remote exception occurs
300      */
revertActiveSessions()301     abstract boolean revertActiveSessions();
302 
303     /**
304      * Abandons the staged session with the given sessionId. Client should handle {@code false}
305      * return value carefully as failure here can leave device in inconsistent state.
306      *
307      * @return {@code true} upon success, {@code false} if any exception occurs
308      */
abortStagedSession(int sessionId)309     abstract boolean abortStagedSession(int sessionId);
310 
311     /**
312      * Uninstalls given {@code apexPackage}.
313      *
314      * <p>NOTE. Device must be rebooted in order for uninstall to take effect.
315      *
316      * @param apexPackagePath package to uninstall.
317      * @return {@code true} upon successful uninstall, {@code false} otherwise.
318      */
uninstallApex(String apexPackagePath)319     abstract boolean uninstallApex(String apexPackagePath);
320 
321     /**
322      * Registers an APK package as an embedded apk of apex.
323      */
registerApkInApex(AndroidPackage pkg)324     abstract void registerApkInApex(AndroidPackage pkg);
325 
326     /**
327      * Reports error raised during installation of apk-in-apex.
328      *
329      * @param scanDirPath the directory of the apex inside which apk-in-apex resides.
330      * @param errorMsg the actual error that occurred when scanning the path
331      */
reportErrorWithApkInApex(String scanDirPath, String errorMsg)332     abstract void reportErrorWithApkInApex(String scanDirPath, String errorMsg);
333 
334     /**
335      * Returns null if there were no errors when installing apk-in-apex inside
336      * {@param apexPackageName}, otherwise returns the error as string
337      *
338      * @param apexPackageName Package name of the apk container of apex
339      */
340     @Nullable
getApkInApexInstallError(String apexPackageName)341     abstract String getApkInApexInstallError(String apexPackageName);
342 
343     /**
344      * Returns list of {@code packageName} of apks inside the given apex.
345      * @param apexPackageName Package name of the apk container of apex
346      */
getApksInApex(String apexPackageName)347     abstract List<String> getApksInApex(String apexPackageName);
348 
349     /**
350      * Returns the apex module name for the given package name, if the package is an APEX. Otherwise
351      * returns {@code null}.
352      */
353     @Nullable
getApexModuleNameForPackageName(String apexPackageName)354     public abstract String getApexModuleNameForPackageName(String apexPackageName);
355 
356     /**
357      * Returns the package name of the active APEX whose name is {@code apexModuleName}. If not
358      * found, returns {@code null}.
359      */
360     @Nullable
getActivePackageNameForApexModuleName(String apexModuleName)361     public abstract String getActivePackageNameForApexModuleName(String apexModuleName);
362 
363     /**
364      * Copies the CE apex data directory for the given {@code userId} to a backup location, for use
365      * in case of rollback.
366      *
367      * @return boolean true if the snapshot was successful
368      */
snapshotCeData(int userId, int rollbackId, String apexPackageName)369     public abstract boolean snapshotCeData(int userId, int rollbackId, String apexPackageName);
370 
371     /**
372      * Restores the snapshot of the CE apex data directory for the given {@code userId}.
373      * Note the snapshot will be deleted after restoration succeeded.
374      *
375      * @return boolean true if the restore was successful
376      */
restoreCeData(int userId, int rollbackId, String apexPackageName)377     public abstract boolean restoreCeData(int userId, int rollbackId, String apexPackageName);
378 
379     /**
380      * Deletes snapshots of the device encrypted apex data directories for the given
381      * {@code rollbackId}.
382      *
383      * @return boolean true if the delete was successful
384      */
destroyDeSnapshots(int rollbackId)385     public abstract boolean destroyDeSnapshots(int rollbackId);
386 
387     /**
388      *  Deletes snapshots of the credential encrypted apex data directories for the specified user,
389      *  for the given rollback id as long as the user is credential unlocked.
390      *
391      * @return boolean true if the delete was successful
392      */
destroyCeSnapshots(int userId, int rollbackId)393     public abstract boolean destroyCeSnapshots(int userId, int rollbackId);
394 
395     /**
396      * Deletes snapshots of the credential encrypted apex data directories for the specified user,
397      * where the rollback id is not included in {@code retainRollbackIds} as long as the user is
398      * credential unlocked.
399      *
400      * @return boolean true if the delete was successful
401      */
destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds)402     public abstract boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds);
403 
404     /**
405      * Inform apexd that the boot has completed.
406      */
markBootCompleted()407     public abstract void markBootCompleted();
408 
409     /**
410      * Estimate how much storage space is needed on /data/ for decompressing apexes
411      * @param infoList List of apexes that are compressed in target build.
412      * @return Size, in bytes, the amount of space needed on /data/
413      */
calculateSizeForCompressedApex(CompressedApexInfoList infoList)414     public abstract long calculateSizeForCompressedApex(CompressedApexInfoList infoList)
415             throws RemoteException;
416 
417     /**
418      * Reserve space on /data so that apexes can be decompressed after OTA
419      * @param infoList List of apexes that are compressed in target build.
420      */
reserveSpaceForCompressedApex(CompressedApexInfoList infoList)421     public abstract void reserveSpaceForCompressedApex(CompressedApexInfoList infoList)
422             throws RemoteException;
423 
424     /**
425      * Performs a non-staged install of the given {@code apexFile}.
426      */
installPackage(File apexFile, PackageParser2 packageParser)427     abstract void installPackage(File apexFile, PackageParser2 packageParser)
428             throws PackageManagerException;
429 
430     /**
431      * Get a list of apex system services implemented in an apex.
432      *
433      * <p>The list is sorted by initOrder for consistency.
434      */
getApexSystemServices()435     public abstract List<ApexSystemServiceInfo> getApexSystemServices();
436 
437     /**
438      * Returns an APEX file backing the mount point {@code file} is located on, or {@code null} if
439      * {@code file} doesn't belong to a {@code /apex} mount point.
440      *
441      * <p>Also returns {@code null} if device doesn't support updatable APEX packages.
442      */
443     @Nullable
getBackingApexFile(@onNull File file)444     public abstract File getBackingApexFile(@NonNull File file);
445 
446     /**
447      * Dumps various state information to the provided {@link PrintWriter} object.
448      *
449      * @param pw the {@link PrintWriter} object to send information to.
450      * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
451      *                    information about that specific package will be dumped.
452      */
dump(PrintWriter pw, @Nullable String packageName)453     abstract void dump(PrintWriter pw, @Nullable String packageName);
454 
455     @IntDef(
456             flag = true,
457             prefix = { "MATCH_"},
458             value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE})
459     @Retention(RetentionPolicy.SOURCE)
460     @interface PackageInfoFlags{}
461 
462     /**
463      * An implementation of {@link ApexManager} that should be used in case device supports updating
464      * APEX packages.
465      */
466     @VisibleForTesting
467     protected static class ApexManagerImpl extends ApexManager {
468         private final Object mLock = new Object();
469 
470         // TODO(ioffe): this should be either List or ArrayMap.
471         @GuardedBy("mLock")
472         private Set<ActiveApexInfo> mActiveApexInfosCache;
473 
474         /**
475          * Map of all apex system services to the jar files they are contained in.
476          */
477         @GuardedBy("mLock")
478         private List<ApexSystemServiceInfo> mApexSystemServices = new ArrayList<>();
479 
480         /**
481          * Contains the list of {@code packageName}s of apks-in-apex for given
482          * {@code apexModuleName}. See {@link #mPackageNameToApexModuleName} to understand the
483          * difference between {@code packageName} and {@code apexModuleName}.
484          */
485         @GuardedBy("mLock")
486         private ArrayMap<String, List<String>> mApksInApex = new ArrayMap<>();
487 
488         /**
489          * Contains the list of {@code Exception}s that were raised when installing apk-in-apex
490          * inside {@code apexModuleName}.
491          */
492         @GuardedBy("mLock")
493         private Map<String, String> mErrorWithApkInApex = new ArrayMap<>();
494 
495         @GuardedBy("mLock")
496         private List<PackageInfo> mAllPackagesCache;
497 
498         /**
499          * An APEX is a file format that delivers the apex-payload wrapped in an apk container. The
500          * apk container has a reference name, called {@code packageName}, which is found inside the
501          * {@code AndroidManifest.xml}. The apex payload inside the container also has a reference
502          * name, called {@code apexModuleName}, which is found in {@code apex_manifest.json} file.
503          *
504          * {@link #mPackageNameToApexModuleName} contains the mapping from {@code packageName} of
505          * the apk container to {@code apexModuleName} of the apex-payload inside.
506          */
507         @GuardedBy("mLock")
508         private ArrayMap<String, String> mPackageNameToApexModuleName;
509 
510         /**
511          * Reverse mapping of {@link #mPackageNameToApexModuleName}, for active packages only.
512          */
513         @GuardedBy("mLock")
514         private ArrayMap<String, String> mApexModuleNameToActivePackageName;
515 
516         /**
517          * Whether an APEX package is active or not.
518          *
519          * @param packageInfo the package to check
520          * @return {@code true} if this package is active, {@code false} otherwise.
521          */
isActive(PackageInfo packageInfo)522         private static boolean isActive(PackageInfo packageInfo) {
523             return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
524         }
525 
526         /**
527          * Retrieve the service from ServiceManager. If the service is not running, it will be
528          * started, and this function will block until it is ready.
529          */
530         @VisibleForTesting
waitForApexService()531         protected IApexService waitForApexService() {
532             // Since apexd is a trusted platform component, synchronized calls are allowable
533             return IApexService.Stub.asInterface(
534                     Binder.allowBlocking(ServiceManager.waitForService("apexservice")));
535         }
536 
537         @Override
getActiveApexInfos()538         public List<ActiveApexInfo> getActiveApexInfos() {
539             final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
540                     Trace.TRACE_TAG_PACKAGE_MANAGER);
541             synchronized (mLock) {
542                 if (mActiveApexInfosCache == null) {
543                     t.traceBegin("getActiveApexInfos_noCache");
544                     try {
545                         mActiveApexInfosCache = new ArraySet<>();
546                         final ApexInfo[] activePackages = waitForApexService().getActivePackages();
547                         for (int i = 0; i < activePackages.length; i++) {
548                             ApexInfo apexInfo = activePackages[i];
549                             mActiveApexInfosCache.add(new ActiveApexInfo(apexInfo));
550                         }
551                     } catch (RemoteException e) {
552                         Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
553                     }
554                     t.traceEnd();
555                 }
556                 if (mActiveApexInfosCache != null) {
557                     return new ArrayList<>(mActiveApexInfosCache);
558                 } else {
559                     return Collections.emptyList();
560                 }
561             }
562         }
563 
564         @Override
scanApexPackagesTraced(@onNull PackageParser2 packageParser, @NonNull ExecutorService executorService)565         void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
566                 @NonNull ExecutorService executorService) {
567             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackagesTraced");
568             try {
569                 synchronized (mLock) {
570                     scanApexPackagesInternalLocked(packageParser, executorService);
571                 }
572             } finally {
573                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
574             }
575         }
576 
577         @GuardedBy("mLock")
scanApexPackagesInternalLocked(PackageParser2 packageParser, ExecutorService executorService)578         private void scanApexPackagesInternalLocked(PackageParser2 packageParser,
579                 ExecutorService executorService) {
580             final ApexInfo[] allPkgs;
581             try {
582                 mAllPackagesCache = new ArrayList<>();
583                 mPackageNameToApexModuleName = new ArrayMap<>();
584                 mApexModuleNameToActivePackageName = new ArrayMap<>();
585                 allPkgs = waitForApexService().getAllPackages();
586             } catch (RemoteException re) {
587                 Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
588                 throw new RuntimeException(re);
589             }
590             if (allPkgs.length == 0) {
591                 return;
592             }
593             final int flags = PackageManager.GET_META_DATA
594                     | PackageManager.GET_SIGNING_CERTIFICATES
595                     | PackageManager.GET_SIGNATURES;
596             ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>();
597             ParallelPackageParser parallelPackageParser =
598                     new ParallelPackageParser(packageParser, executorService);
599 
600             for (ApexInfo ai : allPkgs) {
601                 File apexFile = new File(ai.modulePath);
602                 parallelPackageParser.submit(apexFile,
603                         ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES);
604                 parsingApexInfo.put(apexFile, ai);
605             }
606 
607             HashSet<String> activePackagesSet = new HashSet<>();
608             HashSet<String> factoryPackagesSet = new HashSet<>();
609             // Process results one by one
610             for (int i = 0; i < parsingApexInfo.size(); i++) {
611                 ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
612                 Throwable throwable = parseResult.throwable;
613                 ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
614 
615                 if (throwable == null) {
616                     // Calling hideAsFinal to assign derived fields for the app info flags.
617                     parseResult.parsedPackage.hideAsFinal();
618                     final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate(
619                             parseResult.parsedPackage, ai, flags);
620                     if (packageInfo == null) {
621                         throw new IllegalStateException("Unable to generate package info: "
622                                 + ai.modulePath);
623                     }
624                     mAllPackagesCache.add(packageInfo);
625                     for (ParsedApexSystemService service :
626                             parseResult.parsedPackage.getApexSystemServices()) {
627                         String minSdkVersion = service.getMinSdkVersion();
628                         if (minSdkVersion != null && !UnboundedSdkLevel.isAtLeast(minSdkVersion)) {
629                             Slog.d(TAG, String.format(
630                                     "ApexSystemService %s with min_sdk_version=%s is skipped",
631                                     service.getName(), service.getMinSdkVersion()));
632                             continue;
633                         }
634                         String maxSdkVersion = service.getMaxSdkVersion();
635                         if (maxSdkVersion != null && !UnboundedSdkLevel.isAtMost(maxSdkVersion)) {
636                             Slog.d(TAG, String.format(
637                                     "ApexSystemService %s with max_sdk_version=%s is skipped",
638                                     service.getName(), service.getMaxSdkVersion()));
639                             continue;
640                         }
641 
642                         if (ai.isActive) {
643                             String name = service.getName();
644                             for (int j = 0; j < mApexSystemServices.size(); j++) {
645                                 ApexSystemServiceInfo info = mApexSystemServices.get(j);
646                                 if (info.getName().equals(name)) {
647                                     throw new IllegalStateException(TextUtils.formatSimple(
648                                             "Duplicate apex-system-service %s from %s, %s", name,
649                                             info.mJarPath, service.getJarPath()));
650                                 }
651                             }
652                             ApexSystemServiceInfo info = new ApexSystemServiceInfo(
653                                     service.getName(), service.getJarPath(),
654                                     service.getInitOrder());
655                             mApexSystemServices.add(info);
656                         }
657                     }
658                     Collections.sort(mApexSystemServices);
659                     mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName);
660                     if (ai.isActive) {
661                         if (activePackagesSet.contains(packageInfo.packageName)) {
662                             throw new IllegalStateException(
663                                     "Two active packages have the same name: "
664                                             + packageInfo.packageName);
665                         }
666                         activePackagesSet.add(packageInfo.packageName);
667                         if (mApexModuleNameToActivePackageName.containsKey(ai.moduleName)) {
668                             throw new IllegalStateException(
669                                     "Two active packages have the same APEX module name: "
670                                             + ai.moduleName);
671                         }
672                         mApexModuleNameToActivePackageName.put(
673                                 ai.moduleName, packageInfo.packageName);
674                     }
675                     if (ai.isFactory) {
676                         // Don't throw when the duplicating APEX is VNDK APEX
677                         if (factoryPackagesSet.contains(packageInfo.packageName)
678                                 && !ai.moduleName.startsWith(VNDK_APEX_MODULE_NAME_PREFIX)) {
679                             throw new IllegalStateException(
680                                     "Two factory packages have the same name: "
681                                             + packageInfo.packageName);
682                         }
683                         factoryPackagesSet.add(packageInfo.packageName);
684                     }
685                 } else if (throwable instanceof PackageManagerException) {
686                     final PackageManagerException e = (PackageManagerException) throwable;
687                     // Skip parsing non-coreApp apex file if system is in minimal boot state.
688                     if (e.error == PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED) {
689                         Slog.w(TAG, "Scan apex failed, not a coreApp:" + ai.modulePath);
690                         continue;
691                     }
692                     throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
693                 } else {
694                     throw new IllegalStateException("Unexpected exception occurred while parsing "
695                             + ai.modulePath, throwable);
696                 }
697             }
698         }
699 
700         @Override
701         @Nullable
getPackageInfo(String packageName, @PackageInfoFlags int flags)702         public PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
703             synchronized (mLock) {
704                 Preconditions.checkState(mAllPackagesCache != null,
705                         "APEX packages have not been scanned");
706                 boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
707                 boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
708                 for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
709                     final PackageInfo packageInfo = mAllPackagesCache.get(i);
710                     if (!packageInfo.packageName.equals(packageName)) {
711                         continue;
712                     }
713                     if ((matchActive && isActive(packageInfo))
714                             || (matchFactory && isFactory(packageInfo))) {
715                         return packageInfo;
716                     }
717                 }
718                 return null;
719             }
720         }
721 
722         @Override
getActivePackages()723         List<PackageInfo> getActivePackages() {
724             synchronized (mLock) {
725                 Preconditions.checkState(mAllPackagesCache != null,
726                         "APEX packages have not been scanned");
727                 final List<PackageInfo> activePackages = new ArrayList<>();
728                 for (int i = 0; i < mAllPackagesCache.size(); i++) {
729                     final PackageInfo packageInfo = mAllPackagesCache.get(i);
730                     if (isActive(packageInfo)) {
731                         activePackages.add(packageInfo);
732                     }
733                 }
734                 return activePackages;
735             }
736         }
737 
738         @Override
getFactoryPackages()739         List<PackageInfo> getFactoryPackages() {
740             synchronized (mLock) {
741                 Preconditions.checkState(mAllPackagesCache != null,
742                         "APEX packages have not been scanned");
743                 final List<PackageInfo> factoryPackages = new ArrayList<>();
744                 for (int i = 0; i < mAllPackagesCache.size(); i++) {
745                     final PackageInfo packageInfo = mAllPackagesCache.get(i);
746                     if (isFactory(packageInfo)) {
747                         factoryPackages.add(packageInfo);
748                     }
749                 }
750                 return factoryPackages;
751             }
752         }
753 
754         @Override
getInactivePackages()755         List<PackageInfo> getInactivePackages() {
756             synchronized (mLock) {
757                 Preconditions.checkState(mAllPackagesCache != null,
758                         "APEX packages have not been scanned");
759                 final List<PackageInfo> inactivePackages = new ArrayList<>();
760                 for (int i = 0; i < mAllPackagesCache.size(); i++) {
761                     final PackageInfo packageInfo = mAllPackagesCache.get(i);
762                     if (!isActive(packageInfo)) {
763                         inactivePackages.add(packageInfo);
764                     }
765                 }
766                 return inactivePackages;
767             }
768         }
769 
770         @Override
isApexPackage(String packageName)771         boolean isApexPackage(String packageName) {
772             if (!isApexSupported()) return false;
773             synchronized (mLock) {
774                 Preconditions.checkState(mAllPackagesCache != null,
775                         "APEX packages have not been scanned");
776                 for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
777                     final PackageInfo packageInfo = mAllPackagesCache.get(i);
778                     if (packageInfo.packageName.equals(packageName)) {
779                         return true;
780                     }
781                 }
782             }
783             return false;
784         }
785 
786         @Override
787         @Nullable
getActiveApexPackageNameContainingPackage(String containedPackageName)788         public String getActiveApexPackageNameContainingPackage(String containedPackageName) {
789             Objects.requireNonNull(containedPackageName);
790             synchronized (mLock) {
791                 Preconditions.checkState(mPackageNameToApexModuleName != null,
792                         "APEX packages have not been scanned");
793                 int numApksInApex = mApksInApex.size();
794                 for (int apkInApexNum = 0; apkInApexNum < numApksInApex; apkInApexNum++) {
795                     if (mApksInApex.valueAt(apkInApexNum).contains(containedPackageName)) {
796                         String apexModuleName = mApksInApex.keyAt(apkInApexNum);
797 
798                         int numApexPkgs = mPackageNameToApexModuleName.size();
799                         for (int apexPkgNum = 0; apexPkgNum < numApexPkgs; apexPkgNum++) {
800                             if (mPackageNameToApexModuleName.valueAt(apexPkgNum).equals(
801                                     apexModuleName)) {
802                                 return mPackageNameToApexModuleName.keyAt(apexPkgNum);
803                             }
804                         }
805                     }
806                 }
807             }
808 
809             return null;
810         }
811 
812         @Override
getStagedSessionInfo(int sessionId)813         @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
814             try {
815                 ApexSessionInfo apexSessionInfo =
816                         waitForApexService().getStagedSessionInfo(sessionId);
817                 if (apexSessionInfo.isUnknown) {
818                     return null;
819                 }
820                 return apexSessionInfo;
821             } catch (RemoteException re) {
822                 Slog.e(TAG, "Unable to contact apexservice", re);
823                 throw new RuntimeException(re);
824             }
825         }
826 
827         @Override
getSessions()828         SparseArray<ApexSessionInfo> getSessions() {
829             try {
830                 final ApexSessionInfo[] sessions = waitForApexService().getSessions();
831                 final SparseArray<ApexSessionInfo> result = new SparseArray<>(sessions.length);
832                 for (int i = 0; i < sessions.length; i++) {
833                     result.put(sessions[i].sessionId, sessions[i]);
834                 }
835                 return result;
836             } catch (RemoteException re) {
837                 Slog.e(TAG, "Unable to contact apexservice", re);
838                 throw new RuntimeException(re);
839             }
840         }
841 
842         @Override
submitStagedSession(ApexSessionParams params)843         ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException {
844             try {
845                 final ApexInfoList apexInfoList = new ApexInfoList();
846                 waitForApexService().submitStagedSession(params, apexInfoList);
847                 return apexInfoList;
848             } catch (RemoteException re) {
849                 Slog.e(TAG, "Unable to contact apexservice", re);
850                 throw new RuntimeException(re);
851             } catch (Exception e) {
852                 throw new PackageManagerException(
853                         PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
854                         "apexd verification failed : " + e.getMessage());
855             }
856         }
857 
858         @Override
getStagedApexInfos(ApexSessionParams params)859         ApexInfo[] getStagedApexInfos(ApexSessionParams params) {
860             try {
861                 return waitForApexService().getStagedApexInfos(params);
862             } catch (RemoteException re) {
863                 Slog.w(TAG, "Unable to contact apexservice" + re.getMessage());
864                 throw new RuntimeException(re);
865             } catch (Exception e) {
866                 Slog.w(TAG, "Failed to collect staged apex infos" + e.getMessage());
867                 return new ApexInfo[0];
868             }
869         }
870 
871         @Override
markStagedSessionReady(int sessionId)872         void markStagedSessionReady(int sessionId) throws PackageManagerException {
873             try {
874                 waitForApexService().markStagedSessionReady(sessionId);
875             } catch (RemoteException re) {
876                 Slog.e(TAG, "Unable to contact apexservice", re);
877                 throw new RuntimeException(re);
878             } catch (Exception e) {
879                 throw new PackageManagerException(
880                         PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
881                         "Failed to mark apexd session as ready : " + e.getMessage());
882             }
883         }
884 
885         @Override
markStagedSessionSuccessful(int sessionId)886         void markStagedSessionSuccessful(int sessionId) {
887             try {
888                 waitForApexService().markStagedSessionSuccessful(sessionId);
889             } catch (RemoteException re) {
890                 Slog.e(TAG, "Unable to contact apexservice", re);
891                 throw new RuntimeException(re);
892             } catch (Exception e) {
893                 // It is fine to just log an exception in this case. APEXd will be able to recover
894                 // in case markStagedSessionSuccessful fails.
895                 Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
896             }
897         }
898 
899         @Override
isApexSupported()900         boolean isApexSupported() {
901             return true;
902         }
903 
904         @Override
revertActiveSessions()905         boolean revertActiveSessions() {
906             try {
907                 waitForApexService().revertActiveSessions();
908                 return true;
909             } catch (RemoteException re) {
910                 Slog.e(TAG, "Unable to contact apexservice", re);
911                 return false;
912             } catch (Exception e) {
913                 Slog.e(TAG, e.getMessage(), e);
914                 return false;
915             }
916         }
917 
918         @Override
abortStagedSession(int sessionId)919         boolean abortStagedSession(int sessionId) {
920             try {
921                 waitForApexService().abortStagedSession(sessionId);
922                 return true;
923             } catch (Exception e) {
924                 Slog.e(TAG, e.getMessage(), e);
925                 return false;
926             }
927         }
928 
929         @Override
uninstallApex(String apexPackagePath)930         boolean uninstallApex(String apexPackagePath) {
931             try {
932                 waitForApexService().unstagePackages(Collections.singletonList(apexPackagePath));
933                 return true;
934             } catch (Exception e) {
935                 return false;
936             }
937         }
938 
939         @Override
registerApkInApex(AndroidPackage pkg)940         void registerApkInApex(AndroidPackage pkg) {
941             synchronized (mLock) {
942                 for (ActiveApexInfo aai : mActiveApexInfosCache) {
943                     if (pkg.getBaseApkPath().startsWith(
944                             aai.apexDirectory.getAbsolutePath() + File.separator)) {
945                         List<String> apks = mApksInApex.get(aai.apexModuleName);
946                         if (apks == null) {
947                             apks = Lists.newArrayList();
948                             mApksInApex.put(aai.apexModuleName, apks);
949                         }
950                         Slog.i(TAG, "Registering " + pkg.getPackageName() + " as apk-in-apex of "
951                                 + aai.apexModuleName);
952                         apks.add(pkg.getPackageName());
953                     }
954                 }
955             }
956         }
957 
958         @Override
reportErrorWithApkInApex(String scanDirPath, String errorMsg)959         void reportErrorWithApkInApex(String scanDirPath, String errorMsg) {
960             synchronized (mLock) {
961                 for (ActiveApexInfo aai : mActiveApexInfosCache) {
962                     if (scanDirPath.startsWith(aai.apexDirectory.getAbsolutePath())) {
963                         mErrorWithApkInApex.put(aai.apexModuleName, errorMsg);
964                     }
965                 }
966             }
967         }
968 
969         @Override
970         @Nullable
getApkInApexInstallError(String apexPackageName)971         String getApkInApexInstallError(String apexPackageName) {
972             synchronized (mLock) {
973                 Preconditions.checkState(mPackageNameToApexModuleName != null,
974                         "APEX packages have not been scanned");
975                 String moduleName = mPackageNameToApexModuleName.get(apexPackageName);
976                 if (moduleName == null) {
977                     return null;
978                 }
979                 return mErrorWithApkInApex.get(moduleName);
980             }
981         }
982 
983         @Override
getApksInApex(String apexPackageName)984         List<String> getApksInApex(String apexPackageName) {
985             synchronized (mLock) {
986                 Preconditions.checkState(mPackageNameToApexModuleName != null,
987                         "APEX packages have not been scanned");
988                 String moduleName = mPackageNameToApexModuleName.get(apexPackageName);
989                 if (moduleName == null) {
990                     return Collections.emptyList();
991                 }
992                 return mApksInApex.getOrDefault(moduleName, Collections.emptyList());
993             }
994         }
995 
996         @Override
997         @Nullable
getApexModuleNameForPackageName(String apexPackageName)998         public String getApexModuleNameForPackageName(String apexPackageName) {
999             synchronized (mLock) {
1000                 Preconditions.checkState(mPackageNameToApexModuleName != null,
1001                         "APEX packages have not been scanned");
1002                 return mPackageNameToApexModuleName.get(apexPackageName);
1003             }
1004         }
1005 
1006         @Override
1007         @Nullable
getActivePackageNameForApexModuleName(String apexModuleName)1008         public String getActivePackageNameForApexModuleName(String apexModuleName) {
1009             synchronized (mLock) {
1010                 Preconditions.checkState(mApexModuleNameToActivePackageName != null,
1011                         "APEX packages have not been scanned");
1012                 return mApexModuleNameToActivePackageName.get(apexModuleName);
1013             }
1014         }
1015 
1016         @Override
snapshotCeData(int userId, int rollbackId, String apexPackageName)1017         public boolean snapshotCeData(int userId, int rollbackId, String apexPackageName) {
1018             String apexModuleName;
1019             synchronized (mLock) {
1020                 Preconditions.checkState(mPackageNameToApexModuleName != null,
1021                         "APEX packages have not been scanned");
1022                 apexModuleName = mPackageNameToApexModuleName.get(apexPackageName);
1023             }
1024             if (apexModuleName == null) {
1025                 Slog.e(TAG, "Invalid apex package name: " + apexPackageName);
1026                 return false;
1027             }
1028             try {
1029                 waitForApexService().snapshotCeData(userId, rollbackId, apexModuleName);
1030                 return true;
1031             } catch (Exception e) {
1032                 Slog.e(TAG, e.getMessage(), e);
1033                 return false;
1034             }
1035         }
1036 
1037         @Override
restoreCeData(int userId, int rollbackId, String apexPackageName)1038         public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) {
1039             String apexModuleName;
1040             synchronized (mLock) {
1041                 Preconditions.checkState(mPackageNameToApexModuleName != null,
1042                         "APEX packages have not been scanned");
1043                 apexModuleName = mPackageNameToApexModuleName.get(apexPackageName);
1044             }
1045             if (apexModuleName == null) {
1046                 Slog.e(TAG, "Invalid apex package name: " + apexPackageName);
1047                 return false;
1048             }
1049             try {
1050                 waitForApexService().restoreCeData(userId, rollbackId, apexModuleName);
1051                 return true;
1052             } catch (Exception e) {
1053                 Slog.e(TAG, e.getMessage(), e);
1054                 return false;
1055             }
1056         }
1057 
1058         @Override
destroyDeSnapshots(int rollbackId)1059         public boolean destroyDeSnapshots(int rollbackId) {
1060             try {
1061                 waitForApexService().destroyDeSnapshots(rollbackId);
1062                 return true;
1063             } catch (Exception e) {
1064                 Slog.e(TAG, e.getMessage(), e);
1065                 return false;
1066             }
1067         }
1068 
1069         @Override
destroyCeSnapshots(int userId, int rollbackId)1070         public boolean destroyCeSnapshots(int userId, int rollbackId) {
1071             try {
1072                 waitForApexService().destroyCeSnapshots(userId, rollbackId);
1073                 return true;
1074             } catch (Exception e) {
1075                 Slog.e(TAG, e.getMessage(), e);
1076                 return false;
1077             }
1078         }
1079 
1080         @Override
destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds)1081         public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) {
1082             try {
1083                 waitForApexService().destroyCeSnapshotsNotSpecified(userId, retainRollbackIds);
1084                 return true;
1085             } catch (Exception e) {
1086                 Slog.e(TAG, e.getMessage(), e);
1087                 return false;
1088             }
1089         }
1090 
1091         @Override
markBootCompleted()1092         public void markBootCompleted() {
1093             try {
1094                 waitForApexService().markBootCompleted();
1095             } catch (RemoteException re) {
1096                 Slog.e(TAG, "Unable to contact apexservice", re);
1097             }
1098         }
1099 
1100         @Override
calculateSizeForCompressedApex(CompressedApexInfoList infoList)1101         public long calculateSizeForCompressedApex(CompressedApexInfoList infoList)
1102                 throws RemoteException {
1103             return waitForApexService().calculateSizeForCompressedApex(infoList);
1104         }
1105 
1106         @Override
reserveSpaceForCompressedApex(CompressedApexInfoList infoList)1107         public void reserveSpaceForCompressedApex(CompressedApexInfoList infoList)
1108                 throws RemoteException {
1109             waitForApexService().reserveSpaceForCompressedApex(infoList);
1110         }
1111 
getSigningDetails(PackageInfo pkg)1112         private SigningDetails getSigningDetails(PackageInfo pkg) throws PackageManagerException {
1113             final int minSignatureScheme =
1114                     ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
1115                             pkg.applicationInfo.targetSdkVersion);
1116             final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
1117             final ParseResult<SigningDetails> result = ApkSignatureVerifier.verify(
1118                     input, pkg.applicationInfo.sourceDir, minSignatureScheme);
1119             if (result.isError()) {
1120                 throw new PackageManagerException(result.getErrorCode(), result.getErrorMessage(),
1121                         result.getException());
1122             }
1123             return result.getResult();
1124         }
1125 
checkApexSignature(PackageInfo existingApexPkg, PackageInfo newApexPkg)1126         private void checkApexSignature(PackageInfo existingApexPkg, PackageInfo newApexPkg)
1127                 throws PackageManagerException {
1128             final SigningDetails existingSigningDetails = getSigningDetails(existingApexPkg);
1129             final SigningDetails newSigningDetails = getSigningDetails(newApexPkg);
1130             if (!newSigningDetails.checkCapability(existingSigningDetails,
1131                       SigningDetails.CertCapabilities.INSTALLED_DATA)) {
1132                 throw new PackageManagerException(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
1133                           "APK container signature of " + newApexPkg.applicationInfo.sourceDir
1134                                    + " is not compatible with currently installed on device");
1135             }
1136         }
1137 
1138         @Override
installPackage(File apexFile, PackageParser2 packageParser)1139         void installPackage(File apexFile, PackageParser2 packageParser)
1140                 throws PackageManagerException {
1141             try {
1142                 final int flags = PackageManager.GET_META_DATA
1143                         | PackageManager.GET_SIGNING_CERTIFICATES
1144                         | PackageManager.GET_SIGNATURES;
1145                 final ParsedPackage parsedPackage = packageParser.parsePackage(
1146                         apexFile, flags, /* useCaches= */ false);
1147                 final PackageInfo newApexPkg = PackageInfoWithoutStateUtils.generate(parsedPackage,
1148                         /* apexInfo= */ null, flags);
1149                 if (newApexPkg == null) {
1150                     throw new PackageManagerException(PackageManager.INSTALL_FAILED_INVALID_APK,
1151                             "Failed to generate package info for " + apexFile.getAbsolutePath());
1152                 }
1153                 final PackageInfo existingApexPkg = getPackageInfo(newApexPkg.packageName,
1154                         MATCH_ACTIVE_PACKAGE);
1155                 if (existingApexPkg == null) {
1156                     Slog.w(TAG, "Attempting to install new APEX package " + newApexPkg.packageName);
1157                     throw new PackageManagerException(PackageManager.INSTALL_FAILED_PACKAGE_CHANGED,
1158                             "It is forbidden to install new APEX packages");
1159                 }
1160                 checkApexSignature(existingApexPkg, newApexPkg);
1161                 ApexInfo apexInfo = waitForApexService().installAndActivatePackage(
1162                         apexFile.getAbsolutePath());
1163                 final ParsedPackage parsedPackage2 = packageParser.parsePackage(
1164                         new File(apexInfo.modulePath), flags, /* useCaches= */ false);
1165                 final PackageInfo finalApexPkg = PackageInfoWithoutStateUtils.generate(
1166                         parsedPackage2, apexInfo, flags);
1167                 // Installation was successful, time to update mAllPackagesCache
1168                 synchronized (mLock) {
1169                     if (isFactory(existingApexPkg)) {
1170                         existingApexPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
1171                         mAllPackagesCache.add(finalApexPkg);
1172                     } else {
1173                         for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
1174                             if (mAllPackagesCache.get(i).equals(existingApexPkg)) {
1175                                 mAllPackagesCache.set(i, finalApexPkg);
1176                                 break;
1177                             }
1178                         }
1179                     }
1180                 }
1181             } catch (RemoteException e) {
1182                 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
1183                         "apexservice not available");
1184             } catch (PackageManagerException e) {
1185                 // Catching it in order not to fall back to Exception which rethrows the
1186                 // PackageManagerException with a common error code.
1187                 throw e;
1188             } catch (Exception e) {
1189                 // TODO(b/187864524): is INSTALL_FAILED_INTERNAL_ERROR is the right error code here?
1190                 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
1191                         e.getMessage());
1192             }
1193         }
1194 
1195         @Override
getApexSystemServices()1196         public List<ApexSystemServiceInfo> getApexSystemServices() {
1197             synchronized (mLock) {
1198                 Preconditions.checkState(mApexSystemServices != null,
1199                         "APEX packages have not been scanned");
1200                 return mApexSystemServices;
1201             }
1202         }
1203 
1204         @Override
getBackingApexFile(File file)1205         public File getBackingApexFile(File file) {
1206             Path path = file.toPath();
1207             if (!path.startsWith(Environment.getApexDirectory().toPath())) {
1208                 return null;
1209             }
1210             if (path.getNameCount() < 2) {
1211                 return null;
1212             }
1213             String moduleName = file.toPath().getName(1).toString();
1214             final List<ActiveApexInfo> apexes = getActiveApexInfos();
1215             for (int i = 0; i < apexes.size(); i++) {
1216                 if (apexes.get(i).apexModuleName.equals(moduleName)) {
1217                     return apexes.get(i).apexFile;
1218                 }
1219             }
1220             return null;
1221         }
1222 
1223         /**
1224          * Dump information about the packages contained in a particular cache
1225          * @param packagesCache the cache to print information about.
1226          * @param packageName a {@link String} containing a package name, or {@code null}. If set,
1227          *                    only information about that specific package will be dumped.
1228          * @param ipw the {@link IndentingPrintWriter} object to send information to.
1229          */
dumpFromPackagesCache( List<PackageInfo> packagesCache, @Nullable String packageName, IndentingPrintWriter ipw)1230         void dumpFromPackagesCache(
1231                 List<PackageInfo> packagesCache,
1232                 @Nullable String packageName,
1233                 IndentingPrintWriter ipw) {
1234             ipw.println();
1235             ipw.increaseIndent();
1236             for (int i = 0, size = packagesCache.size(); i < size; i++) {
1237                 final PackageInfo pi = packagesCache.get(i);
1238                 if (packageName != null && !packageName.equals(pi.packageName)) {
1239                     continue;
1240                 }
1241                 ipw.println(pi.packageName);
1242                 ipw.increaseIndent();
1243                 ipw.println("Version: " + pi.versionCode);
1244                 ipw.println("Path: " + pi.applicationInfo.sourceDir);
1245                 ipw.println("IsActive: " + isActive(pi));
1246                 ipw.println("IsFactory: " + isFactory(pi));
1247                 ipw.println("ApplicationInfo: ");
1248                 ipw.increaseIndent();
1249                 pi.applicationInfo.dump(new PrintWriterPrinter(ipw), "");
1250                 ipw.decreaseIndent();
1251                 ipw.decreaseIndent();
1252             }
1253             ipw.decreaseIndent();
1254             ipw.println();
1255         }
1256 
1257         @Override
dump(PrintWriter pw, @Nullable String packageName)1258         void dump(PrintWriter pw, @Nullable String packageName) {
1259             final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
1260             try {
1261                 ipw.println();
1262                 ipw.println("APEX session state:");
1263                 ipw.increaseIndent();
1264                 final ApexSessionInfo[] sessions = waitForApexService().getSessions();
1265                 for (ApexSessionInfo si : sessions) {
1266                     ipw.println("Session ID: " + si.sessionId);
1267                     ipw.increaseIndent();
1268                     if (si.isUnknown) {
1269                         ipw.println("State: UNKNOWN");
1270                     } else if (si.isVerified) {
1271                         ipw.println("State: VERIFIED");
1272                     } else if (si.isStaged) {
1273                         ipw.println("State: STAGED");
1274                     } else if (si.isActivated) {
1275                         ipw.println("State: ACTIVATED");
1276                     } else if (si.isActivationFailed) {
1277                         ipw.println("State: ACTIVATION FAILED");
1278                     } else if (si.isSuccess) {
1279                         ipw.println("State: SUCCESS");
1280                     } else if (si.isRevertInProgress) {
1281                         ipw.println("State: REVERT IN PROGRESS");
1282                     } else if (si.isReverted) {
1283                         ipw.println("State: REVERTED");
1284                     } else if (si.isRevertFailed) {
1285                         ipw.println("State: REVERT FAILED");
1286                     }
1287                     ipw.decreaseIndent();
1288                 }
1289                 ipw.decreaseIndent();
1290                 ipw.println();
1291                 synchronized (mLock) {
1292                     if (mAllPackagesCache == null) {
1293                         ipw.println("APEX packages have not been scanned");
1294                         return;
1295                     }
1296                 }
1297                 ipw.println("Active APEX packages:");
1298                 dumpFromPackagesCache(getActivePackages(), packageName, ipw);
1299                 ipw.println("Inactive APEX packages:");
1300                 dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
1301                 ipw.println("Factory APEX packages:");
1302                 dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
1303             } catch (RemoteException e) {
1304                 ipw.println("Couldn't communicate with apexd.");
1305             }
1306         }
1307     }
1308 
1309     /**
1310      * An implementation of {@link ApexManager} that should be used in case device does not support
1311      * updating APEX packages.
1312      */
1313     @VisibleForTesting
1314     static final class ApexManagerFlattenedApex extends ApexManager {
1315         @Override
getActiveApexInfos()1316         public List<ActiveApexInfo> getActiveApexInfos() {
1317             // There is no apexd running in case of flattened apex
1318             // We look up the /apex directory and identify the active APEX modules from there.
1319             // As "preinstalled" path, we just report /system since in the case of flattened APEX
1320             // the /apex directory is just a symlink to /system/apex.
1321             List<ActiveApexInfo> result = new ArrayList<>();
1322             File apexDir = Environment.getApexDirectory();
1323             if (apexDir.isDirectory()) {
1324                 File[] files = apexDir.listFiles();
1325                 // listFiles might be null if system server doesn't have permission to read
1326                 // a directory.
1327                 if (files != null) {
1328                     for (File file : files) {
1329                         if (file.isDirectory() && !file.getName().contains("@")
1330                                 // In flattened configuration, init special-cases the art directory
1331                                 // and bind-mounts com.android.art.debug to com.android.art.
1332                                 && !file.getName().equals("com.android.art.debug")) {
1333                             result.add(
1334                                     new ActiveApexInfo(file, Environment.getRootDirectory(), file));
1335                         }
1336                     }
1337                 }
1338             }
1339             return result;
1340         }
1341 
1342         @Override
scanApexPackagesTraced(@onNull PackageParser2 packageParser, @NonNull ExecutorService executorService)1343         void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
1344                 @NonNull ExecutorService executorService) {
1345             // No-op
1346         }
1347 
1348         @Override
getPackageInfo(String packageName, int flags)1349         public PackageInfo getPackageInfo(String packageName, int flags) {
1350             return null;
1351         }
1352 
1353         @Override
getActivePackages()1354         List<PackageInfo> getActivePackages() {
1355             return Collections.emptyList();
1356         }
1357 
1358         @Override
getFactoryPackages()1359         List<PackageInfo> getFactoryPackages() {
1360             return Collections.emptyList();
1361         }
1362 
1363         @Override
getInactivePackages()1364         List<PackageInfo> getInactivePackages() {
1365             return Collections.emptyList();
1366         }
1367 
1368         @Override
isApexPackage(String packageName)1369         boolean isApexPackage(String packageName) {
1370             return false;
1371         }
1372 
1373         @Override
1374         @Nullable
getActiveApexPackageNameContainingPackage( @onNull String containedPackageName)1375         public String getActiveApexPackageNameContainingPackage(
1376                 @NonNull String containedPackageName) {
1377             Objects.requireNonNull(containedPackageName);
1378 
1379             return null;
1380         }
1381 
1382         @Override
getStagedSessionInfo(int sessionId)1383         ApexSessionInfo getStagedSessionInfo(int sessionId) {
1384             throw new UnsupportedOperationException();
1385         }
1386 
1387         @Override
getSessions()1388         SparseArray<ApexSessionInfo> getSessions() {
1389             return new SparseArray<>(0);
1390         }
1391 
1392         @Override
submitStagedSession(ApexSessionParams params)1393         ApexInfoList submitStagedSession(ApexSessionParams params)
1394                 throws PackageManagerException {
1395             throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
1396                     "Device doesn't support updating APEX");
1397         }
1398 
1399         @Override
getStagedApexInfos(ApexSessionParams params)1400         ApexInfo[] getStagedApexInfos(ApexSessionParams params) {
1401             throw new UnsupportedOperationException();
1402         }
1403 
1404         @Override
markStagedSessionReady(int sessionId)1405         void markStagedSessionReady(int sessionId) {
1406             throw new UnsupportedOperationException();
1407         }
1408 
1409         @Override
markStagedSessionSuccessful(int sessionId)1410         void markStagedSessionSuccessful(int sessionId) {
1411             throw new UnsupportedOperationException();
1412         }
1413 
1414         @Override
isApexSupported()1415         boolean isApexSupported() {
1416             return false;
1417         }
1418 
1419         @Override
revertActiveSessions()1420         boolean revertActiveSessions() {
1421             throw new UnsupportedOperationException();
1422         }
1423 
1424         @Override
abortStagedSession(int sessionId)1425         boolean abortStagedSession(int sessionId) {
1426             throw new UnsupportedOperationException();
1427         }
1428 
1429         @Override
uninstallApex(String apexPackagePath)1430         boolean uninstallApex(String apexPackagePath) {
1431             throw new UnsupportedOperationException();
1432         }
1433 
1434         @Override
registerApkInApex(AndroidPackage pkg)1435         void registerApkInApex(AndroidPackage pkg) {
1436             // No-op
1437         }
1438 
1439         @Override
reportErrorWithApkInApex(String scanDirPath, String errorMsg)1440         void reportErrorWithApkInApex(String scanDirPath, String errorMsg) {
1441             // No-op
1442         }
1443 
1444         @Override
1445         @Nullable
getApkInApexInstallError(String apexPackageName)1446         String getApkInApexInstallError(String apexPackageName) {
1447             return null;
1448         }
1449 
1450         @Override
getApksInApex(String apexPackageName)1451         List<String> getApksInApex(String apexPackageName) {
1452             return Collections.emptyList();
1453         }
1454 
1455         @Override
1456         @Nullable
getApexModuleNameForPackageName(String apexPackageName)1457         public String getApexModuleNameForPackageName(String apexPackageName) {
1458             return null;
1459         }
1460 
1461         @Override
1462         @Nullable
getActivePackageNameForApexModuleName(String apexModuleName)1463         public String getActivePackageNameForApexModuleName(String apexModuleName) {
1464             return null;
1465         }
1466 
1467         @Override
snapshotCeData(int userId, int rollbackId, String apexPackageName)1468         public boolean snapshotCeData(int userId, int rollbackId, String apexPackageName) {
1469             throw new UnsupportedOperationException();
1470         }
1471 
1472         @Override
restoreCeData(int userId, int rollbackId, String apexPackageName)1473         public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) {
1474             throw new UnsupportedOperationException();
1475         }
1476 
1477         @Override
destroyDeSnapshots(int rollbackId)1478         public boolean destroyDeSnapshots(int rollbackId) {
1479             throw new UnsupportedOperationException();
1480         }
1481 
1482         @Override
destroyCeSnapshots(int userId, int rollbackId)1483         public boolean destroyCeSnapshots(int userId, int rollbackId) {
1484             return true;
1485         }
1486 
1487         @Override
destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds)1488         public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) {
1489             return true;
1490         }
1491 
1492         @Override
markBootCompleted()1493         public void markBootCompleted() {
1494             // No-op
1495         }
1496 
1497         @Override
calculateSizeForCompressedApex(CompressedApexInfoList infoList)1498         public long calculateSizeForCompressedApex(CompressedApexInfoList infoList) {
1499             throw new UnsupportedOperationException();
1500         }
1501 
1502         @Override
reserveSpaceForCompressedApex(CompressedApexInfoList infoList)1503         public void reserveSpaceForCompressedApex(CompressedApexInfoList infoList) {
1504             throw new UnsupportedOperationException();
1505         }
1506 
1507         @Override
installPackage(File apexFile, PackageParser2 packageParser)1508         void installPackage(File apexFile, PackageParser2 packageParser) {
1509             throw new UnsupportedOperationException("APEX updates are not supported");
1510         }
1511 
1512         @Override
getApexSystemServices()1513         public List<ApexSystemServiceInfo> getApexSystemServices() {
1514             // TODO(satayev): we can't really support flattened apex use case, and need to migrate
1515             // the manifest entries into system's manifest asap.
1516             return Collections.emptyList();
1517         }
1518 
1519         @Override
getBackingApexFile(File file)1520         public File getBackingApexFile(File file) {
1521             return null;
1522         }
1523 
1524         @Override
dump(PrintWriter pw, String packageName)1525         void dump(PrintWriter pw, String packageName) {
1526             // No-op
1527         }
1528     }
1529 }
1530