Add MATCH_APEX flag to getInstalledPackages.
If set, PackageManager will query apexservice and ask for activated
packages.
Test: wrote a small app to test the new query.
Bug: 117589375
Change-Id: I498bd97896f3eab65c88e9684874a30713be585e
diff --git a/api/current.txt b/api/current.txt
index b192d7f..cb71160 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -11137,6 +11137,7 @@
field public int[] gids;
field public int installLocation;
field public android.content.pm.InstrumentationInfo[] instrumentation;
+ field public boolean isApex;
field public long lastUpdateTime;
field public java.lang.String packageName;
field public android.content.pm.PermissionInfo[] permissions;
@@ -11528,6 +11529,7 @@
field public static final int INSTALL_REASON_UNKNOWN = 0; // 0x0
field public static final int INSTALL_REASON_USER = 4; // 0x4
field public static final int MATCH_ALL = 131072; // 0x20000
+ field public static final int MATCH_APEX = 1073741824; // 0x40000000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
field public static final int MATCH_DIRECT_BOOT_AUTO = 268435456; // 0x10000000
field public static final int MATCH_DIRECT_BOOT_AWARE = 524288; // 0x80000
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 9e20503..ecdd810 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
+import android.apex.ApexInfo;
import android.os.Parcel;
import android.os.Parcelable;
@@ -390,6 +391,11 @@
@Nullable
public String compileSdkVersionCodename;
+ /**
+ * Whether the package is an APEX package.
+ */
+ public boolean isApex;
+
public PackageInfo() {
}
@@ -472,6 +478,7 @@
} else {
dest.writeInt(0);
}
+ dest.writeBoolean(isApex);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -533,7 +540,7 @@
if (hasSigningInfo != 0) {
signingInfo = SigningInfo.CREATOR.createFromParcel(source);
}
-
+ isApex = source.readBoolean();
// The component lists were flattened with the redundant ApplicationInfo
// instances omitted. Distribute the canonical one here as appropriate.
if (applicationInfo != null) {
@@ -544,6 +551,15 @@
}
}
+ /**
+ * @hide
+ */
+ public PackageInfo(ApexInfo apexInfo) {
+ packageName = apexInfo.packageName;
+ setLongVersionCode(apexInfo.versionCode);
+ isApex = true;
+ }
+
private void propagateApplicationInfo(ApplicationInfo appInfo, ComponentInfo[] components) {
if (components != null) {
for (ComponentInfo ci : components) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e14b17e..361beba 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -145,6 +145,7 @@
MATCH_FACTORY_ONLY,
MATCH_DEBUG_TRIAGED_MISSING,
MATCH_INSTANT,
+ MATCH_APEX,
GET_DISABLED_COMPONENTS,
GET_DISABLED_UNTIL_USED_COMPONENTS,
GET_UNINSTALLED_PACKAGES,
@@ -540,6 +541,17 @@
public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 0x20000000;
/**
+ * {@link PackageInfo} flag: include APEX packages that are currently
+ * installed. In APEX terminology, this corresponds to packages that are
+ * currently active, i.e. mounted and available to other processes of the OS.
+ * In particular, this flag alone will not match APEX files that are staged
+ * for activation at next reboot.
+ * TODO(b/119767311): include uninstalled/inactive APEX if
+ * MATCH_UNINSTALLED_PACKAGES is set.
+ */
+ public static final int MATCH_APEX = 0x40000000;
+
+ /**
* Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when
* resolving an intent that matches the {@code CrossProfileIntentFilter},
* the current profile will be skipped. Only activities in the target user
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e4e8010..9856a2b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -68,6 +68,7 @@
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.content.pm.PackageManager.MATCH_APEX;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
@@ -125,6 +126,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.apex.ApexInfo;
+import android.apex.IApexService;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppDetailsActivity;
@@ -7727,6 +7730,8 @@
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForPackage(flags, userId, null);
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
+ final boolean listApex = (flags & MATCH_APEX) != 0;
+
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */,
"get installed packages");
@@ -7765,7 +7770,22 @@
}
}
}
-
+ if (listApex) {
+ final IApexService apex = IApexService.Stub.asInterface(
+ ServiceManager.getService("apexservice"));
+ if (apex != null) {
+ try {
+ final ApexInfo[] activePkgs = apex.getActivePackages();
+ for (ApexInfo apexInfo : activePkgs) {
+ list.add(new PackageInfo(apexInfo));
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to retrieve packages from apexservice: " + e.toString());
+ }
+ } else {
+ Log.e(TAG, "Unable to connect to apexservice for querying packages.");
+ }
+ }
return new ParceledListSlice<>(list);
}
}