summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/PackageParser.java18
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageParserTest.java14
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java210
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java24
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");