Loading services/core/java/com/android/server/pm/ApexManager.java +103 −406 File changed.Preview size limit exceeded, changes collapsed. Show changes services/core/java/com/android/server/pm/ApexPackageInfo.java 0 → 100644 +376 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pm; import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE; import static com.android.server.pm.ApexManager.MATCH_FACTORY_PACKAGE; import android.annotation.NonNull; import android.annotation.Nullable; import android.apex.ApexInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.util.ArrayMap; import android.util.PrintWriterPrinter; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils; import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.concurrent.ExecutorService; /** * A temporary holder to store PackageInfo for scanned apex packages. We will unify the scan/install * flows of APK and APEX and PMS will be the only source of truth for all package information * including both APK and APEX. This class will no longer be needed when the migration is done. */ class ApexPackageInfo { private static final String TAG = "ApexManager"; private static final String VNDK_APEX_MODULE_NAME_PREFIX = "com.android.vndk."; private final Object mLock = new Object(); @GuardedBy("mLock") private List<PackageInfo> mAllPackagesCache; /** * Whether an APEX package is active or not. * * @param packageInfo the package to check * @return {@code true} if this package is active, {@code false} otherwise. */ private static boolean isActive(PackageInfo packageInfo) { return packageInfo.isActiveApex; } /** * Called by package manager service to scan apex package files when device boots up. * * @param allPackages All apex packages to scan. * @param packageParser The package parser to support apex package parsing and caching parsed * results. * @param executorService An executor to support parallel package parsing. */ List<ApexManager.ScanResult> scanApexPackages(ApexInfo[] allPackages, @NonNull PackageParser2 packageParser, @NonNull ExecutorService executorService) { synchronized (mLock) { return scanApexPackagesInternalLocked(allPackages, packageParser, executorService); } } /** * Retrieves information about an APEX package. * * @param packageName the package name to look for. Note that this is the package name reported * in the APK container manifest (i.e. AndroidManifest.xml), which might * differ from the one reported in the APEX manifest (i.e. * apex_manifest.json). * @param flags the type of package to return. This may match to active packages * and factory (pre-installed) packages. * @return a PackageInfo object with the information about the package, or null if the package * is not found. */ @Nullable PackageInfo getPackageInfo(String packageName, @ApexManager.PackageInfoFlags int flags) { synchronized (mLock) { Preconditions.checkState(mAllPackagesCache != null, "APEX packages have not been scanned"); boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0; boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0; for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { final PackageInfo packageInfo = mAllPackagesCache.get(i); if (!packageInfo.packageName.equals(packageName)) { continue; } if ((matchActive && isActive(packageInfo)) || (matchFactory && isFactory(packageInfo))) { return packageInfo; } } return null; } } /** * Retrieves information about all active APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active package. */ List<PackageInfo> getActivePackages() { synchronized (mLock) { Preconditions.checkState(mAllPackagesCache != null, "APEX packages have not been scanned"); final List<PackageInfo> activePackages = new ArrayList<>(); for (int i = 0; i < mAllPackagesCache.size(); i++) { final PackageInfo packageInfo = mAllPackagesCache.get(i); if (isActive(packageInfo)) { activePackages.add(packageInfo); } } return activePackages; } } /** * Retrieves information about all active pre-installed APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active pre-installed package. */ List<PackageInfo> getFactoryPackages() { synchronized (mLock) { Preconditions.checkState(mAllPackagesCache != null, "APEX packages have not been scanned"); final List<PackageInfo> factoryPackages = new ArrayList<>(); for (int i = 0; i < mAllPackagesCache.size(); i++) { final PackageInfo packageInfo = mAllPackagesCache.get(i); if (isFactory(packageInfo)) { factoryPackages.add(packageInfo); } } return factoryPackages; } } /** * Retrieves information about all inactive APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * inactive package. */ List<PackageInfo> getInactivePackages() { synchronized (mLock) { Preconditions.checkState(mAllPackagesCache != null, "APEX packages have not been scanned"); final List<PackageInfo> inactivePackages = new ArrayList<>(); for (int i = 0; i < mAllPackagesCache.size(); i++) { final PackageInfo packageInfo = mAllPackagesCache.get(i); if (!isActive(packageInfo)) { inactivePackages.add(packageInfo); } } return inactivePackages; } } /** * Checks if {@code packageName} is an apex package. * * @param packageName package to check. * @return {@code true} if {@code packageName} is an apex package. */ boolean isApexPackage(String packageName) { synchronized (mLock) { Preconditions.checkState(mAllPackagesCache != null, "APEX packages have not been scanned"); for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { final PackageInfo packageInfo = mAllPackagesCache.get(i); if (packageInfo.packageName.equals(packageName)) { return true; } } } return false; } /** * Called by ApexManager to update cached PackageInfo when installing rebootless APEX. */ void notifyPackageInstalled(PackageInfo oldApexPkg, PackageInfo newApexPkg) { synchronized (mLock) { for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { if (mAllPackagesCache.get(i).equals(oldApexPkg)) { if (isFactory(oldApexPkg)) { oldApexPkg.isActiveApex = false; mAllPackagesCache.add(newApexPkg); } else { mAllPackagesCache.set(i, newApexPkg); } break; } } } } /** * Whether the APEX package is pre-installed or not. * * @param packageInfo the package to check * @return {@code true} if this package is pre-installed, {@code false} otherwise. */ private static boolean isFactory(@NonNull PackageInfo packageInfo) { return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0; } /** * Dumps various state information to the provided {@link PrintWriter} object. * * @param pw the {@link PrintWriter} object to send information to. * @param packageName a {@link String} containing a package name, or {@code null}. If set, only * information about that specific package will be dumped. */ void dump(PrintWriter pw, @Nullable String packageName) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); synchronized (mLock) { if (mAllPackagesCache == null) { ipw.println("APEX packages have not been scanned"); return; } } ipw.println("Active APEX packages:"); dumpFromPackagesCache(getActivePackages(), packageName, ipw); ipw.println("Inactive APEX packages:"); dumpFromPackagesCache(getInactivePackages(), packageName, ipw); ipw.println("Factory APEX packages:"); dumpFromPackagesCache(getFactoryPackages(), packageName, ipw); } @GuardedBy("mLock") private void notifyScanResultLocked(List<ApexManager.ScanResult> scanResults) { mAllPackagesCache = new ArrayList<>(); final int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_SIGNATURES; HashSet<String> activePackagesSet = new HashSet<>(); HashSet<String> factoryPackagesSet = new HashSet<>(); for (ApexManager.ScanResult result : scanResults) { ApexInfo ai = result.apexInfo; final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate( result.parsedPackage, ai, flags); if (packageInfo == null) { throw new IllegalStateException("Unable to generate package info: " + ai.modulePath); } if (!packageInfo.packageName.equals(result.packageName)) { throw new IllegalStateException("Unmatched package name: " + result.packageName + " != " + packageInfo.packageName + ", path=" + ai.modulePath); } mAllPackagesCache.add(packageInfo); if (ai.isActive) { if (!activePackagesSet.add(packageInfo.packageName)) { throw new IllegalStateException( "Two active packages have the same name: " + packageInfo.packageName); } } if (ai.isFactory) { // Don't throw when the duplicating APEX is VNDK APEX if (!factoryPackagesSet.add(packageInfo.packageName) && !ai.moduleName.startsWith(VNDK_APEX_MODULE_NAME_PREFIX)) { throw new IllegalStateException( "Two factory packages have the same name: " + packageInfo.packageName); } } } } @GuardedBy("mLock") private List<ApexManager.ScanResult> scanApexPackagesInternalLocked(final ApexInfo[] allPkgs, PackageParser2 packageParser, ExecutorService executorService) { if (allPkgs == null || allPkgs.length == 0) { notifyScanResultLocked(Collections.EMPTY_LIST); return Collections.EMPTY_LIST; } ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>(); ParallelPackageParser parallelPackageParser = new ParallelPackageParser(packageParser, executorService); for (ApexInfo ai : allPkgs) { File apexFile = new File(ai.modulePath); parallelPackageParser.submit(apexFile, ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES); parsingApexInfo.put(apexFile, ai); } List<ApexManager.ScanResult> results = new ArrayList<>(parsingApexInfo.size()); // Process results one by one for (int i = 0; i < parsingApexInfo.size(); i++) { ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take(); Throwable throwable = parseResult.throwable; ApexInfo ai = parsingApexInfo.get(parseResult.scanFile); if (throwable == null) { // Calling hideAsFinal to assign derived fields for the app info flags. parseResult.parsedPackage.hideAsFinal(); results.add(new ApexManager.ScanResult( ai, parseResult.parsedPackage, parseResult.parsedPackage.getPackageName())); } else if (throwable instanceof PackageManagerException) { final PackageManagerException e = (PackageManagerException) throwable; // Skip parsing non-coreApp apex file if system is in minimal boot state. if (e.error == PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED) { Slog.w(TAG, "Scan apex failed, not a coreApp:" + ai.modulePath); continue; } throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable); } else { throw new IllegalStateException("Unexpected exception occurred while parsing " + ai.modulePath, throwable); } } notifyScanResultLocked(results); return results; } /** * Dump information about the packages contained in a particular cache * @param packagesCache the cache to print information about. * @param packageName a {@link String} containing a package name, or {@code null}. If set, * only information about that specific package will be dumped. * @param ipw the {@link IndentingPrintWriter} object to send information to. */ private static void dumpFromPackagesCache(List<PackageInfo> packagesCache, @Nullable String packageName, IndentingPrintWriter ipw) { ipw.println(); ipw.increaseIndent(); for (int i = 0, size = packagesCache.size(); i < size; i++) { final PackageInfo pi = packagesCache.get(i); if (packageName != null && !packageName.equals(pi.packageName)) { continue; } ipw.println(pi.packageName); ipw.increaseIndent(); ipw.println("Version: " + pi.versionCode); ipw.println("Path: " + pi.applicationInfo.sourceDir); ipw.println("IsActive: " + isActive(pi)); ipw.println("IsFactory: " + isFactory(pi)); ipw.println("ApplicationInfo: "); ipw.increaseIndent(); pi.applicationInfo.dump(new PrintWriterPrinter(ipw), ""); ipw.decreaseIndent(); ipw.decreaseIndent(); } ipw.decreaseIndent(); ipw.println(); } } services/core/java/com/android/server/pm/ComputerEngine.java +8 −6 Original line number Diff line number Diff line Loading @@ -397,6 +397,7 @@ public class ComputerEngine implements Computer { private final UserManagerService mUserManager; private final PermissionManagerServiceInternal mPermissionManager; private final ApexManager mApexManager; private final ApexPackageInfo mApexPackageInfo; private final PackageManagerServiceInjector mInjector; private final ComponentResolverApi mComponentResolver; private final InstantAppResolverConnection mInstantAppResolverConnection; Loading Loading @@ -450,6 +451,7 @@ public class ComputerEngine implements Computer { mContext = args.service.mContext; mInjector = args.service.mInjector; mApexManager = args.service.mApexManager; mApexPackageInfo = args.service.mApexPackageInfo; mInstantAppResolverConnection = args.service.mInstantAppResolverConnection; mDefaultAppProvider = args.service.getDefaultAppProvider(); mDomainVerificationManager = args.service.mDomainVerificationManager; Loading Loading @@ -999,7 +1001,7 @@ public class ComputerEngine implements Computer { if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { apexFlags = ApexManager.MATCH_FACTORY_PACKAGE; } final PackageInfo pi = mApexManager.getPackageInfo(packageName, apexFlags); final PackageInfo pi = mApexPackageInfo.getPackageInfo(packageName, apexFlags); if (pi == null) { return null; } Loading Loading @@ -1696,7 +1698,7 @@ public class ComputerEngine implements Computer { if (matchFactoryOnly) { // Instant app filtering for APEX modules is ignored if ((flags & MATCH_APEX) != 0) { return mApexManager.getPackageInfo(packageName, return mApexPackageInfo.getPackageInfo(packageName, ApexManager.MATCH_FACTORY_PACKAGE); } final PackageStateInternal ps = mSettings.getDisabledSystemPkg(packageName); Loading Loading @@ -1741,7 +1743,7 @@ public class ComputerEngine implements Computer { return generatePackageInfo(ps, flags, userId); } if ((flags & MATCH_APEX) != 0) { return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); return mApexPackageInfo.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); } return null; } Loading Loading @@ -1837,9 +1839,9 @@ public class ComputerEngine implements Computer { } if (listApex) { if (listFactory) { list.addAll(mApexManager.getFactoryPackages()); list.addAll(mApexPackageInfo.getFactoryPackages()); } else { list.addAll(mApexManager.getActivePackages()); list.addAll(mApexPackageInfo.getActivePackages()); } } return new ParceledListSlice<>(list); Loading Loading @@ -5048,7 +5050,7 @@ public class ComputerEngine implements Computer { final PackageStateInternal ps = mSettings.getPackage(packageName); // Installer info for Apex is not stored in PackageManager if (ps == null && mApexManager.isApexPackage(packageName)) { if (ps == null && mApexPackageInfo.isApexPackage(packageName)) { return InstallSource.EMPTY; } Loading services/core/java/com/android/server/pm/DumpHelper.java +6 −2 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import java.io.PrintWriter; final class DumpHelper { private final PermissionManagerServiceInternal mPermissionManager; private final ApexManager mApexManager; private final ApexPackageInfo mApexPackageInfo; private final StorageEventHelper mStorageEventHelper; private final DomainVerificationManagerInternal mDomainVerificationManager; private final PackageInstallerService mInstallerService; Loading @@ -64,6 +65,7 @@ final class DumpHelper { DumpHelper( PermissionManagerServiceInternal permissionManager, ApexManager apexManager, ApexPackageInfo apexPackageInfo, StorageEventHelper storageEventHelper, DomainVerificationManagerInternal domainVerificationManager, PackageInstallerService installerService, String requiredVerifierPackage, Loading @@ -74,6 +76,7 @@ final class DumpHelper { PerUidReadTimeouts[] perUidReadTimeouts) { mPermissionManager = permissionManager; mApexManager = apexManager; mApexPackageInfo = apexPackageInfo; mStorageEventHelper = storageEventHelper; mDomainVerificationManager = domainVerificationManager; mInstallerService = installerService; Loading Loading @@ -271,7 +274,7 @@ final class DumpHelper { // Return if the package doesn't exist. if (packageName != null && snapshot.getPackageStateInternal(packageName) == null && !mApexManager.isApexPackage(packageName)) { && !mApexPackageInfo.isApexPackage(packageName)) { pw.println("Unable to find package: " + packageName); return; } Loading Loading @@ -555,8 +558,9 @@ final class DumpHelper { if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX) && (packageName == null || mApexManager.isApexPackage(packageName))) { && (packageName == null || mApexPackageInfo.isApexPackage(packageName))) { mApexManager.dump(pw, packageName); mApexPackageInfo.dump(pw, packageName); } if (!checkin Loading services/core/java/com/android/server/pm/InitAppsHelper.java +17 −2 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ final class InitAppsHelper { private final int mSystemScanFlags; private final InstallPackageHelper mInstallPackageHelper; private final ApexManager mApexManager; private final ApexPackageInfo mApexPackageInfo; private final ExecutorService mExecutorService; /* Tracks how long system scan took */ private long mSystemScanTime; Loading @@ -96,11 +97,13 @@ final class InitAppsHelper { private final List<String> mStubSystemApps = new ArrayList<>(); // TODO(b/198166813): remove PMS dependency InitAppsHelper(PackageManagerService pm, ApexManager apexManager, InitAppsHelper(PackageManagerService pm, ApexManager apexManager, ApexPackageInfo apexPackageInfo, InstallPackageHelper installPackageHelper, List<ScanPartition> systemPartitions) { mPm = pm; mApexManager = apexManager; mApexPackageInfo = apexPackageInfo; mInstallPackageHelper = installPackageHelper; mSystemPartitions = systemPartitions; mDirsToScanAsSystem = getSystemScanPartitions(); Loading Loading @@ -179,6 +182,17 @@ final class InitAppsHelper { return null; } @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) private List<ApexManager.ScanResult> scanApexPackagesTraced(PackageParser2 packageParser) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackages"); try { return mApexPackageInfo.scanApexPackages( mApexManager.getAllApexInfos(), packageParser, mExecutorService); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** * Install apps from system dirs. */ Loading @@ -188,7 +202,8 @@ final class InitAppsHelper { int[] userIds, long startTime) { // Prepare apex package info before scanning APKs, this information is needed when // scanning apk in apex. mApexManager.scanApexPackagesTraced(packageParser, mExecutorService); final List<ApexManager.ScanResult> apexScanResults = scanApexPackagesTraced(packageParser); mApexManager.notifyScanResult(apexScanResults); scanSystemDirs(packageParser, mExecutorService); // Parse overlay configuration files to set default enable state, mutability, and Loading Loading
services/core/java/com/android/server/pm/ApexManager.java +103 −406 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/core/java/com/android/server/pm/ApexPackageInfo.java 0 → 100644 +376 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pm; import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE; import static com.android.server.pm.ApexManager.MATCH_FACTORY_PACKAGE; import android.annotation.NonNull; import android.annotation.Nullable; import android.apex.ApexInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.util.ArrayMap; import android.util.PrintWriterPrinter; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils; import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.concurrent.ExecutorService; /** * A temporary holder to store PackageInfo for scanned apex packages. We will unify the scan/install * flows of APK and APEX and PMS will be the only source of truth for all package information * including both APK and APEX. This class will no longer be needed when the migration is done. */ class ApexPackageInfo { private static final String TAG = "ApexManager"; private static final String VNDK_APEX_MODULE_NAME_PREFIX = "com.android.vndk."; private final Object mLock = new Object(); @GuardedBy("mLock") private List<PackageInfo> mAllPackagesCache; /** * Whether an APEX package is active or not. * * @param packageInfo the package to check * @return {@code true} if this package is active, {@code false} otherwise. */ private static boolean isActive(PackageInfo packageInfo) { return packageInfo.isActiveApex; } /** * Called by package manager service to scan apex package files when device boots up. * * @param allPackages All apex packages to scan. * @param packageParser The package parser to support apex package parsing and caching parsed * results. * @param executorService An executor to support parallel package parsing. */ List<ApexManager.ScanResult> scanApexPackages(ApexInfo[] allPackages, @NonNull PackageParser2 packageParser, @NonNull ExecutorService executorService) { synchronized (mLock) { return scanApexPackagesInternalLocked(allPackages, packageParser, executorService); } } /** * Retrieves information about an APEX package. * * @param packageName the package name to look for. Note that this is the package name reported * in the APK container manifest (i.e. AndroidManifest.xml), which might * differ from the one reported in the APEX manifest (i.e. * apex_manifest.json). * @param flags the type of package to return. This may match to active packages * and factory (pre-installed) packages. * @return a PackageInfo object with the information about the package, or null if the package * is not found. */ @Nullable PackageInfo getPackageInfo(String packageName, @ApexManager.PackageInfoFlags int flags) { synchronized (mLock) { Preconditions.checkState(mAllPackagesCache != null, "APEX packages have not been scanned"); boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0; boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0; for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { final PackageInfo packageInfo = mAllPackagesCache.get(i); if (!packageInfo.packageName.equals(packageName)) { continue; } if ((matchActive && isActive(packageInfo)) || (matchFactory && isFactory(packageInfo))) { return packageInfo; } } return null; } } /** * Retrieves information about all active APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active package. */ List<PackageInfo> getActivePackages() { synchronized (mLock) { Preconditions.checkState(mAllPackagesCache != null, "APEX packages have not been scanned"); final List<PackageInfo> activePackages = new ArrayList<>(); for (int i = 0; i < mAllPackagesCache.size(); i++) { final PackageInfo packageInfo = mAllPackagesCache.get(i); if (isActive(packageInfo)) { activePackages.add(packageInfo); } } return activePackages; } } /** * Retrieves information about all active pre-installed APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * active pre-installed package. */ List<PackageInfo> getFactoryPackages() { synchronized (mLock) { Preconditions.checkState(mAllPackagesCache != null, "APEX packages have not been scanned"); final List<PackageInfo> factoryPackages = new ArrayList<>(); for (int i = 0; i < mAllPackagesCache.size(); i++) { final PackageInfo packageInfo = mAllPackagesCache.get(i); if (isFactory(packageInfo)) { factoryPackages.add(packageInfo); } } return factoryPackages; } } /** * Retrieves information about all inactive APEX packages. * * @return a List of PackageInfo object, each one containing information about a different * inactive package. */ List<PackageInfo> getInactivePackages() { synchronized (mLock) { Preconditions.checkState(mAllPackagesCache != null, "APEX packages have not been scanned"); final List<PackageInfo> inactivePackages = new ArrayList<>(); for (int i = 0; i < mAllPackagesCache.size(); i++) { final PackageInfo packageInfo = mAllPackagesCache.get(i); if (!isActive(packageInfo)) { inactivePackages.add(packageInfo); } } return inactivePackages; } } /** * Checks if {@code packageName} is an apex package. * * @param packageName package to check. * @return {@code true} if {@code packageName} is an apex package. */ boolean isApexPackage(String packageName) { synchronized (mLock) { Preconditions.checkState(mAllPackagesCache != null, "APEX packages have not been scanned"); for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { final PackageInfo packageInfo = mAllPackagesCache.get(i); if (packageInfo.packageName.equals(packageName)) { return true; } } } return false; } /** * Called by ApexManager to update cached PackageInfo when installing rebootless APEX. */ void notifyPackageInstalled(PackageInfo oldApexPkg, PackageInfo newApexPkg) { synchronized (mLock) { for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) { if (mAllPackagesCache.get(i).equals(oldApexPkg)) { if (isFactory(oldApexPkg)) { oldApexPkg.isActiveApex = false; mAllPackagesCache.add(newApexPkg); } else { mAllPackagesCache.set(i, newApexPkg); } break; } } } } /** * Whether the APEX package is pre-installed or not. * * @param packageInfo the package to check * @return {@code true} if this package is pre-installed, {@code false} otherwise. */ private static boolean isFactory(@NonNull PackageInfo packageInfo) { return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0; } /** * Dumps various state information to the provided {@link PrintWriter} object. * * @param pw the {@link PrintWriter} object to send information to. * @param packageName a {@link String} containing a package name, or {@code null}. If set, only * information about that specific package will be dumped. */ void dump(PrintWriter pw, @Nullable String packageName) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); synchronized (mLock) { if (mAllPackagesCache == null) { ipw.println("APEX packages have not been scanned"); return; } } ipw.println("Active APEX packages:"); dumpFromPackagesCache(getActivePackages(), packageName, ipw); ipw.println("Inactive APEX packages:"); dumpFromPackagesCache(getInactivePackages(), packageName, ipw); ipw.println("Factory APEX packages:"); dumpFromPackagesCache(getFactoryPackages(), packageName, ipw); } @GuardedBy("mLock") private void notifyScanResultLocked(List<ApexManager.ScanResult> scanResults) { mAllPackagesCache = new ArrayList<>(); final int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_SIGNATURES; HashSet<String> activePackagesSet = new HashSet<>(); HashSet<String> factoryPackagesSet = new HashSet<>(); for (ApexManager.ScanResult result : scanResults) { ApexInfo ai = result.apexInfo; final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate( result.parsedPackage, ai, flags); if (packageInfo == null) { throw new IllegalStateException("Unable to generate package info: " + ai.modulePath); } if (!packageInfo.packageName.equals(result.packageName)) { throw new IllegalStateException("Unmatched package name: " + result.packageName + " != " + packageInfo.packageName + ", path=" + ai.modulePath); } mAllPackagesCache.add(packageInfo); if (ai.isActive) { if (!activePackagesSet.add(packageInfo.packageName)) { throw new IllegalStateException( "Two active packages have the same name: " + packageInfo.packageName); } } if (ai.isFactory) { // Don't throw when the duplicating APEX is VNDK APEX if (!factoryPackagesSet.add(packageInfo.packageName) && !ai.moduleName.startsWith(VNDK_APEX_MODULE_NAME_PREFIX)) { throw new IllegalStateException( "Two factory packages have the same name: " + packageInfo.packageName); } } } } @GuardedBy("mLock") private List<ApexManager.ScanResult> scanApexPackagesInternalLocked(final ApexInfo[] allPkgs, PackageParser2 packageParser, ExecutorService executorService) { if (allPkgs == null || allPkgs.length == 0) { notifyScanResultLocked(Collections.EMPTY_LIST); return Collections.EMPTY_LIST; } ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>(); ParallelPackageParser parallelPackageParser = new ParallelPackageParser(packageParser, executorService); for (ApexInfo ai : allPkgs) { File apexFile = new File(ai.modulePath); parallelPackageParser.submit(apexFile, ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES); parsingApexInfo.put(apexFile, ai); } List<ApexManager.ScanResult> results = new ArrayList<>(parsingApexInfo.size()); // Process results one by one for (int i = 0; i < parsingApexInfo.size(); i++) { ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take(); Throwable throwable = parseResult.throwable; ApexInfo ai = parsingApexInfo.get(parseResult.scanFile); if (throwable == null) { // Calling hideAsFinal to assign derived fields for the app info flags. parseResult.parsedPackage.hideAsFinal(); results.add(new ApexManager.ScanResult( ai, parseResult.parsedPackage, parseResult.parsedPackage.getPackageName())); } else if (throwable instanceof PackageManagerException) { final PackageManagerException e = (PackageManagerException) throwable; // Skip parsing non-coreApp apex file if system is in minimal boot state. if (e.error == PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED) { Slog.w(TAG, "Scan apex failed, not a coreApp:" + ai.modulePath); continue; } throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable); } else { throw new IllegalStateException("Unexpected exception occurred while parsing " + ai.modulePath, throwable); } } notifyScanResultLocked(results); return results; } /** * Dump information about the packages contained in a particular cache * @param packagesCache the cache to print information about. * @param packageName a {@link String} containing a package name, or {@code null}. If set, * only information about that specific package will be dumped. * @param ipw the {@link IndentingPrintWriter} object to send information to. */ private static void dumpFromPackagesCache(List<PackageInfo> packagesCache, @Nullable String packageName, IndentingPrintWriter ipw) { ipw.println(); ipw.increaseIndent(); for (int i = 0, size = packagesCache.size(); i < size; i++) { final PackageInfo pi = packagesCache.get(i); if (packageName != null && !packageName.equals(pi.packageName)) { continue; } ipw.println(pi.packageName); ipw.increaseIndent(); ipw.println("Version: " + pi.versionCode); ipw.println("Path: " + pi.applicationInfo.sourceDir); ipw.println("IsActive: " + isActive(pi)); ipw.println("IsFactory: " + isFactory(pi)); ipw.println("ApplicationInfo: "); ipw.increaseIndent(); pi.applicationInfo.dump(new PrintWriterPrinter(ipw), ""); ipw.decreaseIndent(); ipw.decreaseIndent(); } ipw.decreaseIndent(); ipw.println(); } }
services/core/java/com/android/server/pm/ComputerEngine.java +8 −6 Original line number Diff line number Diff line Loading @@ -397,6 +397,7 @@ public class ComputerEngine implements Computer { private final UserManagerService mUserManager; private final PermissionManagerServiceInternal mPermissionManager; private final ApexManager mApexManager; private final ApexPackageInfo mApexPackageInfo; private final PackageManagerServiceInjector mInjector; private final ComponentResolverApi mComponentResolver; private final InstantAppResolverConnection mInstantAppResolverConnection; Loading Loading @@ -450,6 +451,7 @@ public class ComputerEngine implements Computer { mContext = args.service.mContext; mInjector = args.service.mInjector; mApexManager = args.service.mApexManager; mApexPackageInfo = args.service.mApexPackageInfo; mInstantAppResolverConnection = args.service.mInstantAppResolverConnection; mDefaultAppProvider = args.service.getDefaultAppProvider(); mDomainVerificationManager = args.service.mDomainVerificationManager; Loading Loading @@ -999,7 +1001,7 @@ public class ComputerEngine implements Computer { if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { apexFlags = ApexManager.MATCH_FACTORY_PACKAGE; } final PackageInfo pi = mApexManager.getPackageInfo(packageName, apexFlags); final PackageInfo pi = mApexPackageInfo.getPackageInfo(packageName, apexFlags); if (pi == null) { return null; } Loading Loading @@ -1696,7 +1698,7 @@ public class ComputerEngine implements Computer { if (matchFactoryOnly) { // Instant app filtering for APEX modules is ignored if ((flags & MATCH_APEX) != 0) { return mApexManager.getPackageInfo(packageName, return mApexPackageInfo.getPackageInfo(packageName, ApexManager.MATCH_FACTORY_PACKAGE); } final PackageStateInternal ps = mSettings.getDisabledSystemPkg(packageName); Loading Loading @@ -1741,7 +1743,7 @@ public class ComputerEngine implements Computer { return generatePackageInfo(ps, flags, userId); } if ((flags & MATCH_APEX) != 0) { return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); return mApexPackageInfo.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); } return null; } Loading Loading @@ -1837,9 +1839,9 @@ public class ComputerEngine implements Computer { } if (listApex) { if (listFactory) { list.addAll(mApexManager.getFactoryPackages()); list.addAll(mApexPackageInfo.getFactoryPackages()); } else { list.addAll(mApexManager.getActivePackages()); list.addAll(mApexPackageInfo.getActivePackages()); } } return new ParceledListSlice<>(list); Loading Loading @@ -5048,7 +5050,7 @@ public class ComputerEngine implements Computer { final PackageStateInternal ps = mSettings.getPackage(packageName); // Installer info for Apex is not stored in PackageManager if (ps == null && mApexManager.isApexPackage(packageName)) { if (ps == null && mApexPackageInfo.isApexPackage(packageName)) { return InstallSource.EMPTY; } Loading
services/core/java/com/android/server/pm/DumpHelper.java +6 −2 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import java.io.PrintWriter; final class DumpHelper { private final PermissionManagerServiceInternal mPermissionManager; private final ApexManager mApexManager; private final ApexPackageInfo mApexPackageInfo; private final StorageEventHelper mStorageEventHelper; private final DomainVerificationManagerInternal mDomainVerificationManager; private final PackageInstallerService mInstallerService; Loading @@ -64,6 +65,7 @@ final class DumpHelper { DumpHelper( PermissionManagerServiceInternal permissionManager, ApexManager apexManager, ApexPackageInfo apexPackageInfo, StorageEventHelper storageEventHelper, DomainVerificationManagerInternal domainVerificationManager, PackageInstallerService installerService, String requiredVerifierPackage, Loading @@ -74,6 +76,7 @@ final class DumpHelper { PerUidReadTimeouts[] perUidReadTimeouts) { mPermissionManager = permissionManager; mApexManager = apexManager; mApexPackageInfo = apexPackageInfo; mStorageEventHelper = storageEventHelper; mDomainVerificationManager = domainVerificationManager; mInstallerService = installerService; Loading Loading @@ -271,7 +274,7 @@ final class DumpHelper { // Return if the package doesn't exist. if (packageName != null && snapshot.getPackageStateInternal(packageName) == null && !mApexManager.isApexPackage(packageName)) { && !mApexPackageInfo.isApexPackage(packageName)) { pw.println("Unable to find package: " + packageName); return; } Loading Loading @@ -555,8 +558,9 @@ final class DumpHelper { if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX) && (packageName == null || mApexManager.isApexPackage(packageName))) { && (packageName == null || mApexPackageInfo.isApexPackage(packageName))) { mApexManager.dump(pw, packageName); mApexPackageInfo.dump(pw, packageName); } if (!checkin Loading
services/core/java/com/android/server/pm/InitAppsHelper.java +17 −2 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ final class InitAppsHelper { private final int mSystemScanFlags; private final InstallPackageHelper mInstallPackageHelper; private final ApexManager mApexManager; private final ApexPackageInfo mApexPackageInfo; private final ExecutorService mExecutorService; /* Tracks how long system scan took */ private long mSystemScanTime; Loading @@ -96,11 +97,13 @@ final class InitAppsHelper { private final List<String> mStubSystemApps = new ArrayList<>(); // TODO(b/198166813): remove PMS dependency InitAppsHelper(PackageManagerService pm, ApexManager apexManager, InitAppsHelper(PackageManagerService pm, ApexManager apexManager, ApexPackageInfo apexPackageInfo, InstallPackageHelper installPackageHelper, List<ScanPartition> systemPartitions) { mPm = pm; mApexManager = apexManager; mApexPackageInfo = apexPackageInfo; mInstallPackageHelper = installPackageHelper; mSystemPartitions = systemPartitions; mDirsToScanAsSystem = getSystemScanPartitions(); Loading Loading @@ -179,6 +182,17 @@ final class InitAppsHelper { return null; } @GuardedBy({"mPm.mInstallLock", "mPm.mLock"}) private List<ApexManager.ScanResult> scanApexPackagesTraced(PackageParser2 packageParser) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackages"); try { return mApexPackageInfo.scanApexPackages( mApexManager.getAllApexInfos(), packageParser, mExecutorService); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** * Install apps from system dirs. */ Loading @@ -188,7 +202,8 @@ final class InitAppsHelper { int[] userIds, long startTime) { // Prepare apex package info before scanning APKs, this information is needed when // scanning apk in apex. mApexManager.scanApexPackagesTraced(packageParser, mExecutorService); final List<ApexManager.ScanResult> apexScanResults = scanApexPackagesTraced(packageParser); mApexManager.notifyScanResult(apexScanResults); scanSystemDirs(packageParser, mExecutorService); // Parse overlay configuration files to set default enable state, mutability, and Loading