Loading core/java/android/content/pm/PackageParser.java +14 −4 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.apex.ApexInfo; import android.app.ActivityTaskManager; import android.app.ActivityThread; import android.app.ResourcesManager; Loading Loading @@ -8382,20 +8383,29 @@ public class PackageParser { * PackageInfo parser specifically for apex files. * NOTE: It will collect certificates * * @param apexFile * @param apexInfo * @return PackageInfo * @throws PackageParserException */ public static PackageInfo generatePackageInfoFromApex(File apexFile, int flags) public static PackageInfo generatePackageInfoFromApex(ApexInfo apexInfo, int flags) throws PackageParserException { PackageParser pp = new PackageParser(); File apexFile = new File(apexInfo.packagePath); final Package p = pp.parsePackage(apexFile, flags, false); PackageUserState state = new PackageUserState(); PackageInfo pi = generatePackageInfo(p, EmptyArray.INT, flags, 0, 0, Collections.emptySet(), state); pi.applicationInfo.sourceDir = apexFile.getPath(); pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED; if (apexInfo.isFactory) { pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; } else { pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; } if (apexInfo.isActive) { pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED; } else { pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED; } pi.isApex = true; // Collect certificates Loading core/tests/coretests/src/android/content/pm/PackageParserTest.java +12 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.apex.ApexInfo; import android.content.Context; import android.content.pm.PackageParser.Component; import android.content.pm.PackageParser.Package; Loading Loading @@ -497,10 +498,17 @@ public class PackageParserTest { @Test public void testApexPackageInfoGeneration() throws Exception { File apexFile = copyRawResourceToFile("com.android.tzdata.apex", String apexPackageName = "com.android.tzdata.apex"; File apexFile = copyRawResourceToFile(apexPackageName, R.raw.com_android_tzdata); ApexInfo apexInfo = new ApexInfo(); apexInfo.isActive = true; apexInfo.isFactory = false; apexInfo.packageName = apexPackageName; apexInfo.packagePath = apexFile.getPath(); apexInfo.versionCode = 191000070; int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES; PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexFile, flags); PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexInfo, flags); assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName); assertTrue(pi.applicationInfo.enabled); assertEquals(28, pi.applicationInfo.targetSdkVersion); Loading @@ -515,5 +523,7 @@ public class PackageParserTest { assertNotNull(pi.signingInfo); assertTrue(pi.signingInfo.getApkContentsSigners().length > 0); assertTrue(pi.isApex); assertTrue((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0); assertTrue((pi.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0); } } services/core/java/com/android/server/pm/ApexManager.java +168 −42 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.pm; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.apex.ApexInfo; Loading @@ -26,6 +27,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; Loading @@ -42,8 +44,13 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.File; import java.io.PrintWriter; import java.util.Collection; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; /** * ApexManager class handles communications with the apex service to perform operation and queries, Loading @@ -59,10 +66,10 @@ class ApexManager { * AndroidManifest.xml} * * <p>Note that key of this map is {@code packageName} field of the corresponding {@code * AndroidManfiset.xml}. * AndroidManifest.xml}. */ @GuardedBy("mLock") private ArrayMap<String, PackageInfo> mActivePackagesCache; private List<PackageInfo> mAllPackagesCache; /** * A map from {@code apexName} to the {@Link PackageInfo} generated from the {@code * AndroidManifest.xml}. Loading @@ -74,6 +81,7 @@ class ApexManager { @GuardedBy("mLock") private ArrayMap<String, PackageInfo> mApexNameToPackageInfoCache; ApexManager(Context context) { try { mApexService = IApexService.Stub.asInterface( Loading @@ -84,6 +92,15 @@ class ApexManager { mContext = context; } static final int MATCH_ACTIVE_PACKAGE = 1 << 0; static final int MATCH_FACTORY_PACKAGE = 1 << 1; @IntDef( flag = true, prefix = { "MATCH_"}, value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE}) @Retention(RetentionPolicy.SOURCE) @interface PackageInfoFlags{} void systemReady() { mContext.registerReceiver(new BroadcastReceiver() { @Override Loading @@ -94,16 +111,18 @@ class ApexManager { }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); } private void populateActivePackagesCacheIfNeeded() { private void populateAllPackagesCacheIfNeeded() { synchronized (mLock) { if (mActivePackagesCache != null) { if (mAllPackagesCache != null) { return; } mActivePackagesCache = new ArrayMap<>(); mApexNameToPackageInfoCache = new ArrayMap<>(); try { final ApexInfo[] activePkgs = mApexService.getActivePackages(); for (ApexInfo ai : activePkgs) { mAllPackagesCache = new ArrayList<>(); HashSet<String> activePackagesSet = new HashSet<>(); HashSet<String> factoryPackagesSet = new HashSet<>(); final ApexInfo[] allPkgs = mApexService.getAllPackages(); for (ApexInfo ai : allPkgs) { // If the device is using flattened APEX, don't report any APEX // packages since they won't be managed or updated by PackageManager. if ((new File(ai.packagePath)).isDirectory()) { Loading @@ -111,11 +130,27 @@ class ApexManager { } try { final PackageInfo pkg = PackageParser.generatePackageInfoFromApex( new File(ai.packagePath), PackageManager.GET_META_DATA ai, PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES); mActivePackagesCache.put(pkg.packageName, pkg); mAllPackagesCache.add(pkg); if (ai.isActive) { if (activePackagesSet.contains(pkg.packageName)) { throw new IllegalStateException( "Two active packages have the same name: " + pkg.packageName); } activePackagesSet.add(ai.packageName); // TODO(b/132324953): remove. mApexNameToPackageInfoCache.put(ai.packageName, pkg); } if (ai.isFactory) { if (factoryPackagesSet.contains(pkg.packageName)) { throw new IllegalStateException( "Two factory packages have the same name: " + pkg.packageName); } factoryPackagesSet.add(ai.packageName); } } catch (PackageParserException pe) { throw new IllegalStateException("Unable to parse: " + ai, pe); } Loading @@ -128,41 +163,85 @@ class ApexManager { } /** * Retrieves information about an active APEX package. * 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 getActivePackage(String packageName) { populateActivePackagesCacheIfNeeded(); return mActivePackagesCache.get(packageName); @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) { populateAllPackagesCacheIfNeeded(); boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0; boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0; for (PackageInfo packageInfo: mAllPackagesCache) { if (!packageInfo.packageName.equals(packageName)) { continue; } if ((!matchActive || isActive(packageInfo)) && (!matchFactory || isFactory(packageInfo))) { return packageInfo; } } return null; } /** * Returns a {@link PackageInfo} for an APEX package keyed by it's {@code apexName}. * Returns a {@link PackageInfo} for an active APEX package keyed by it's {@code apexName}. * * @deprecated this API will soon be deleted, please don't depend on it. */ // TODO(b/132324953): delete. @Deprecated @Nullable PackageInfo getPackageInfoForApexName(String apexName) { populateActivePackagesCacheIfNeeded(); populateAllPackagesCacheIfNeeded(); return mApexNameToPackageInfoCache.get(apexName); } /** * Retrieves information about all active APEX packages. * * @return a Collection of PackageInfo object, each one containing information about a different * @return a List of PackageInfo object, each one containing information about a different * active package. */ Collection<PackageInfo> getActivePackages() { populateActivePackagesCacheIfNeeded(); return mActivePackagesCache.values(); List<PackageInfo> getActivePackages() { populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() .filter(item -> isActive(item)) .collect(Collectors.toList()); } /** * 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() { populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() .filter(item -> isFactory(item)) .collect(Collectors.toList()); } /** * 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() { populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() .filter(item -> !isActive(item)) .collect(Collectors.toList()); } /** Loading @@ -172,8 +251,13 @@ class ApexManager { * @return {@code true} if {@code packageName} is an apex package. */ boolean isApexPackage(String packageName) { populateActivePackagesCacheIfNeeded(); return mActivePackagesCache.containsKey(packageName); populateAllPackagesCacheIfNeeded(); for (PackageInfo packageInfo : mAllPackagesCache) { if (packageInfo.packageName.equals(packageName)) { return true; } } return false; } /** Loading Loading @@ -301,20 +385,39 @@ class ApexManager { } /** * Dumps various state information to the provided {@link PrintWriter} object. * Whether an APEX package is active or not. * * @param pw the {@link PrintWriter} object to send information to. * @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.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0; } /** * 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(PackageInfo packageInfo) { return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } /** * 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. */ void dump(PrintWriter pw, @Nullable String packageName) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); void dumpFromPackagesCache( List<PackageInfo> packagesCache, @Nullable String packageName, IndentingPrintWriter ipw) { ipw.println(); ipw.println("Active APEX packages:"); ipw.increaseIndent(); try { populateActivePackagesCacheIfNeeded(); for (PackageInfo pi : mActivePackagesCache.values()) { for (PackageInfo pi : packagesCache) { if (packageName != null && !packageName.equals(pi.packageName)) { continue; } Loading @@ -322,10 +425,33 @@ class ApexManager { ipw.increaseIndent(); ipw.println("Version: " + pi.versionCode); ipw.println("Path: " + pi.applicationInfo.sourceDir); ipw.println("IsActive: " + isActive(pi)); ipw.println("IsFactory: " + isFactory(pi)); ipw.decreaseIndent(); } ipw.decreaseIndent(); ipw.println(); } /** * 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); try { populateAllPackagesCacheIfNeeded(); ipw.println(); 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); ipw.increaseIndent(); ipw.println("APEX session state:"); ipw.increaseIndent(); final ApexSessionInfo[] sessions = mApexService.getSessions(); Loading Loading @@ -360,6 +486,6 @@ class ApexManager { } public void onBootCompleted() { populateActivePackagesCacheIfNeeded(); populateAllPackagesCacheIfNeeded(); } } No newline at end of file services/core/java/com/android/server/pm/PackageManagerService.java +17 −7 Original line number Diff line number Diff line Loading @@ -4220,6 +4220,11 @@ public class PackageManagerService extends IPackageManager.Stub final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0; if (matchFactoryOnly) { // Instant app filtering for APEX modules is ignored if ((flags & MATCH_APEX) != 0) { return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_FACTORY_PACKAGE); } final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName); if (ps != null) { if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) { Loading @@ -4230,7 +4235,6 @@ public class PackageManagerService extends IPackageManager.Stub } return generatePackageInfo(ps, flags, userId); } // TODO(b/123680735): support MATCH_APEX|MATCH_FACTORY_ONLY case } PackageParser.Package p = mPackages.get(packageName); Loading Loading @@ -4260,9 +4264,8 @@ public class PackageManagerService extends IPackageManager.Stub } return generatePackageInfo(ps, flags, userId); } // if (!matchFactoryOnly && (flags & MATCH_APEX) != 0) { return mApexManager.getActivePackage(packageName); return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); } } return null; Loading Loading @@ -8558,6 +8561,7 @@ public class PackageManagerService extends IPackageManager.Stub flags = updateFlagsForPackage(flags, userId, null); final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0; final boolean listApex = (flags & MATCH_APEX) != 0; final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0; mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, Loading Loading @@ -8598,10 +8602,15 @@ public class PackageManagerService extends IPackageManager.Stub } } if (listApex) { // TODO(b/119767311): include uninstalled/inactive APEX if // MATCH_UNINSTALLED_PACKAGES is set. if (listFactory) { list.addAll(mApexManager.getFactoryPackages()); } else { list.addAll(mApexManager.getActivePackages()); } if (listUninstalled) { list.addAll(mApexManager.getInactivePackages()); } } return new ParceledListSlice<>(list); } } Loading Loading @@ -24890,7 +24899,8 @@ public class PackageManagerService extends IPackageManager.Stub return; } final ApexManager am = PackageManagerService.this.mApexManager; PackageInfo activePackage = am.getActivePackage(packageName); PackageInfo activePackage = am.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); if (activePackage == null) { adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED, packageName + " is not an apex package"); Loading
core/java/android/content/pm/PackageParser.java +14 −4 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.apex.ApexInfo; import android.app.ActivityTaskManager; import android.app.ActivityThread; import android.app.ResourcesManager; Loading Loading @@ -8382,20 +8383,29 @@ public class PackageParser { * PackageInfo parser specifically for apex files. * NOTE: It will collect certificates * * @param apexFile * @param apexInfo * @return PackageInfo * @throws PackageParserException */ public static PackageInfo generatePackageInfoFromApex(File apexFile, int flags) public static PackageInfo generatePackageInfoFromApex(ApexInfo apexInfo, int flags) throws PackageParserException { PackageParser pp = new PackageParser(); File apexFile = new File(apexInfo.packagePath); final Package p = pp.parsePackage(apexFile, flags, false); PackageUserState state = new PackageUserState(); PackageInfo pi = generatePackageInfo(p, EmptyArray.INT, flags, 0, 0, Collections.emptySet(), state); pi.applicationInfo.sourceDir = apexFile.getPath(); pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED; if (apexInfo.isFactory) { pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; } else { pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; } if (apexInfo.isActive) { pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED; } else { pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED; } pi.isApex = true; // Collect certificates Loading
core/tests/coretests/src/android/content/pm/PackageParserTest.java +12 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.apex.ApexInfo; import android.content.Context; import android.content.pm.PackageParser.Component; import android.content.pm.PackageParser.Package; Loading Loading @@ -497,10 +498,17 @@ public class PackageParserTest { @Test public void testApexPackageInfoGeneration() throws Exception { File apexFile = copyRawResourceToFile("com.android.tzdata.apex", String apexPackageName = "com.android.tzdata.apex"; File apexFile = copyRawResourceToFile(apexPackageName, R.raw.com_android_tzdata); ApexInfo apexInfo = new ApexInfo(); apexInfo.isActive = true; apexInfo.isFactory = false; apexInfo.packageName = apexPackageName; apexInfo.packagePath = apexFile.getPath(); apexInfo.versionCode = 191000070; int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES; PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexFile, flags); PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexInfo, flags); assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName); assertTrue(pi.applicationInfo.enabled); assertEquals(28, pi.applicationInfo.targetSdkVersion); Loading @@ -515,5 +523,7 @@ public class PackageParserTest { assertNotNull(pi.signingInfo); assertTrue(pi.signingInfo.getApkContentsSigners().length > 0); assertTrue(pi.isApex); assertTrue((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0); assertTrue((pi.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0); } }
services/core/java/com/android/server/pm/ApexManager.java +168 −42 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.pm; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.apex.ApexInfo; Loading @@ -26,6 +27,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; Loading @@ -42,8 +44,13 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.File; import java.io.PrintWriter; import java.util.Collection; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; /** * ApexManager class handles communications with the apex service to perform operation and queries, Loading @@ -59,10 +66,10 @@ class ApexManager { * AndroidManifest.xml} * * <p>Note that key of this map is {@code packageName} field of the corresponding {@code * AndroidManfiset.xml}. * AndroidManifest.xml}. */ @GuardedBy("mLock") private ArrayMap<String, PackageInfo> mActivePackagesCache; private List<PackageInfo> mAllPackagesCache; /** * A map from {@code apexName} to the {@Link PackageInfo} generated from the {@code * AndroidManifest.xml}. Loading @@ -74,6 +81,7 @@ class ApexManager { @GuardedBy("mLock") private ArrayMap<String, PackageInfo> mApexNameToPackageInfoCache; ApexManager(Context context) { try { mApexService = IApexService.Stub.asInterface( Loading @@ -84,6 +92,15 @@ class ApexManager { mContext = context; } static final int MATCH_ACTIVE_PACKAGE = 1 << 0; static final int MATCH_FACTORY_PACKAGE = 1 << 1; @IntDef( flag = true, prefix = { "MATCH_"}, value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE}) @Retention(RetentionPolicy.SOURCE) @interface PackageInfoFlags{} void systemReady() { mContext.registerReceiver(new BroadcastReceiver() { @Override Loading @@ -94,16 +111,18 @@ class ApexManager { }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); } private void populateActivePackagesCacheIfNeeded() { private void populateAllPackagesCacheIfNeeded() { synchronized (mLock) { if (mActivePackagesCache != null) { if (mAllPackagesCache != null) { return; } mActivePackagesCache = new ArrayMap<>(); mApexNameToPackageInfoCache = new ArrayMap<>(); try { final ApexInfo[] activePkgs = mApexService.getActivePackages(); for (ApexInfo ai : activePkgs) { mAllPackagesCache = new ArrayList<>(); HashSet<String> activePackagesSet = new HashSet<>(); HashSet<String> factoryPackagesSet = new HashSet<>(); final ApexInfo[] allPkgs = mApexService.getAllPackages(); for (ApexInfo ai : allPkgs) { // If the device is using flattened APEX, don't report any APEX // packages since they won't be managed or updated by PackageManager. if ((new File(ai.packagePath)).isDirectory()) { Loading @@ -111,11 +130,27 @@ class ApexManager { } try { final PackageInfo pkg = PackageParser.generatePackageInfoFromApex( new File(ai.packagePath), PackageManager.GET_META_DATA ai, PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES); mActivePackagesCache.put(pkg.packageName, pkg); mAllPackagesCache.add(pkg); if (ai.isActive) { if (activePackagesSet.contains(pkg.packageName)) { throw new IllegalStateException( "Two active packages have the same name: " + pkg.packageName); } activePackagesSet.add(ai.packageName); // TODO(b/132324953): remove. mApexNameToPackageInfoCache.put(ai.packageName, pkg); } if (ai.isFactory) { if (factoryPackagesSet.contains(pkg.packageName)) { throw new IllegalStateException( "Two factory packages have the same name: " + pkg.packageName); } factoryPackagesSet.add(ai.packageName); } } catch (PackageParserException pe) { throw new IllegalStateException("Unable to parse: " + ai, pe); } Loading @@ -128,41 +163,85 @@ class ApexManager { } /** * Retrieves information about an active APEX package. * 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 getActivePackage(String packageName) { populateActivePackagesCacheIfNeeded(); return mActivePackagesCache.get(packageName); @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) { populateAllPackagesCacheIfNeeded(); boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0; boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0; for (PackageInfo packageInfo: mAllPackagesCache) { if (!packageInfo.packageName.equals(packageName)) { continue; } if ((!matchActive || isActive(packageInfo)) && (!matchFactory || isFactory(packageInfo))) { return packageInfo; } } return null; } /** * Returns a {@link PackageInfo} for an APEX package keyed by it's {@code apexName}. * Returns a {@link PackageInfo} for an active APEX package keyed by it's {@code apexName}. * * @deprecated this API will soon be deleted, please don't depend on it. */ // TODO(b/132324953): delete. @Deprecated @Nullable PackageInfo getPackageInfoForApexName(String apexName) { populateActivePackagesCacheIfNeeded(); populateAllPackagesCacheIfNeeded(); return mApexNameToPackageInfoCache.get(apexName); } /** * Retrieves information about all active APEX packages. * * @return a Collection of PackageInfo object, each one containing information about a different * @return a List of PackageInfo object, each one containing information about a different * active package. */ Collection<PackageInfo> getActivePackages() { populateActivePackagesCacheIfNeeded(); return mActivePackagesCache.values(); List<PackageInfo> getActivePackages() { populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() .filter(item -> isActive(item)) .collect(Collectors.toList()); } /** * 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() { populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() .filter(item -> isFactory(item)) .collect(Collectors.toList()); } /** * 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() { populateAllPackagesCacheIfNeeded(); return mAllPackagesCache .stream() .filter(item -> !isActive(item)) .collect(Collectors.toList()); } /** Loading @@ -172,8 +251,13 @@ class ApexManager { * @return {@code true} if {@code packageName} is an apex package. */ boolean isApexPackage(String packageName) { populateActivePackagesCacheIfNeeded(); return mActivePackagesCache.containsKey(packageName); populateAllPackagesCacheIfNeeded(); for (PackageInfo packageInfo : mAllPackagesCache) { if (packageInfo.packageName.equals(packageName)) { return true; } } return false; } /** Loading Loading @@ -301,20 +385,39 @@ class ApexManager { } /** * Dumps various state information to the provided {@link PrintWriter} object. * Whether an APEX package is active or not. * * @param pw the {@link PrintWriter} object to send information to. * @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.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0; } /** * 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(PackageInfo packageInfo) { return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } /** * 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. */ void dump(PrintWriter pw, @Nullable String packageName) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); void dumpFromPackagesCache( List<PackageInfo> packagesCache, @Nullable String packageName, IndentingPrintWriter ipw) { ipw.println(); ipw.println("Active APEX packages:"); ipw.increaseIndent(); try { populateActivePackagesCacheIfNeeded(); for (PackageInfo pi : mActivePackagesCache.values()) { for (PackageInfo pi : packagesCache) { if (packageName != null && !packageName.equals(pi.packageName)) { continue; } Loading @@ -322,10 +425,33 @@ class ApexManager { ipw.increaseIndent(); ipw.println("Version: " + pi.versionCode); ipw.println("Path: " + pi.applicationInfo.sourceDir); ipw.println("IsActive: " + isActive(pi)); ipw.println("IsFactory: " + isFactory(pi)); ipw.decreaseIndent(); } ipw.decreaseIndent(); ipw.println(); } /** * 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); try { populateAllPackagesCacheIfNeeded(); ipw.println(); 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); ipw.increaseIndent(); ipw.println("APEX session state:"); ipw.increaseIndent(); final ApexSessionInfo[] sessions = mApexService.getSessions(); Loading Loading @@ -360,6 +486,6 @@ class ApexManager { } public void onBootCompleted() { populateActivePackagesCacheIfNeeded(); populateAllPackagesCacheIfNeeded(); } } No newline at end of file
services/core/java/com/android/server/pm/PackageManagerService.java +17 −7 Original line number Diff line number Diff line Loading @@ -4220,6 +4220,11 @@ public class PackageManagerService extends IPackageManager.Stub final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0; if (matchFactoryOnly) { // Instant app filtering for APEX modules is ignored if ((flags & MATCH_APEX) != 0) { return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_FACTORY_PACKAGE); } final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName); if (ps != null) { if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) { Loading @@ -4230,7 +4235,6 @@ public class PackageManagerService extends IPackageManager.Stub } return generatePackageInfo(ps, flags, userId); } // TODO(b/123680735): support MATCH_APEX|MATCH_FACTORY_ONLY case } PackageParser.Package p = mPackages.get(packageName); Loading Loading @@ -4260,9 +4264,8 @@ public class PackageManagerService extends IPackageManager.Stub } return generatePackageInfo(ps, flags, userId); } // if (!matchFactoryOnly && (flags & MATCH_APEX) != 0) { return mApexManager.getActivePackage(packageName); return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); } } return null; Loading Loading @@ -8558,6 +8561,7 @@ public class PackageManagerService extends IPackageManager.Stub flags = updateFlagsForPackage(flags, userId, null); final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0; final boolean listApex = (flags & MATCH_APEX) != 0; final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0; mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, Loading Loading @@ -8598,10 +8602,15 @@ public class PackageManagerService extends IPackageManager.Stub } } if (listApex) { // TODO(b/119767311): include uninstalled/inactive APEX if // MATCH_UNINSTALLED_PACKAGES is set. if (listFactory) { list.addAll(mApexManager.getFactoryPackages()); } else { list.addAll(mApexManager.getActivePackages()); } if (listUninstalled) { list.addAll(mApexManager.getInactivePackages()); } } return new ParceledListSlice<>(list); } } Loading Loading @@ -24890,7 +24899,8 @@ public class PackageManagerService extends IPackageManager.Stub return; } final ApexManager am = PackageManagerService.this.mApexManager; PackageInfo activePackage = am.getActivePackage(packageName); PackageInfo activePackage = am.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE); if (activePackage == null) { adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED, packageName + " is not an apex package");