diff options
4 files changed, 211 insertions, 55 deletions
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 7522bfb25b7a..89be0000ca0e 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -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; @@ -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 diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java index 50e915d688d0..71d9a46eaa24 100644 --- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java +++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java @@ -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; @@ -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); @@ -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); } } diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index dd2d300f35d8..6971ba3ad0bf 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -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; @@ -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; @@ -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, @@ -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}. @@ -74,6 +81,7 @@ class ApexManager { @GuardedBy("mLock") private ArrayMap<String, PackageInfo> mApexNameToPackageInfoCache; + ApexManager(Context context) { try { mApexService = IApexService.Stub.asInterface( @@ -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 @@ -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()) { @@ -111,11 +130,27 @@ class ApexManager { } try { final PackageInfo pkg = PackageParser.generatePackageInfoFromApex( - new File(ai.packagePath), PackageManager.GET_META_DATA - | PackageManager.GET_SIGNING_CERTIFICATES); - mActivePackagesCache.put(pkg.packageName, pkg); - // TODO(b/132324953): remove. - mApexNameToPackageInfoCache.put(ai.packageName, pkg); + ai, PackageManager.GET_META_DATA + | PackageManager.GET_SIGNING_CERTIFICATES); + 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); } @@ -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()); } /** @@ -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; } /** @@ -301,6 +385,55 @@ class ApexManager { } /** + * 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.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 dumpFromPackagesCache( + List<PackageInfo> packagesCache, + @Nullable String packageName, + IndentingPrintWriter ipw) { + ipw.println(); + ipw.increaseIndent(); + for (PackageInfo pi : packagesCache) { + 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.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. @@ -309,23 +442,16 @@ class ApexManager { */ void dump(PrintWriter pw, @Nullable String packageName) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); - ipw.println(); - ipw.println("Active APEX packages:"); - ipw.increaseIndent(); try { - populateActivePackagesCacheIfNeeded(); - for (PackageInfo pi : mActivePackagesCache.values()) { - 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.decreaseIndent(); - } - ipw.decreaseIndent(); + 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(); @@ -360,6 +486,6 @@ class ApexManager { } public void onBootCompleted() { - populateActivePackagesCacheIfNeeded(); + populateAllPackagesCacheIfNeeded(); } -} +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 84470f9c2838..2a61feea6349 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -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)) { @@ -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); @@ -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; @@ -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 */, @@ -8598,9 +8602,14 @@ public class PackageManagerService extends IPackageManager.Stub } } if (listApex) { - // TODO(b/119767311): include uninstalled/inactive APEX if - // MATCH_UNINSTALLED_PACKAGES is set. - list.addAll(mApexManager.getActivePackages()); + if (listFactory) { + list.addAll(mApexManager.getFactoryPackages()); + } else { + list.addAll(mApexManager.getActivePackages()); + } + if (listUninstalled) { + list.addAll(mApexManager.getInactivePackages()); + } } return new ParceledListSlice<>(list); } @@ -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"); |