summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author lpeter <lpeter@google.com> 2023-10-26 12:05:07 +0000
committer lpeter <lpeter@google.com> 2023-11-20 14:41:06 +0000
commit76c2c47c9f84be86a57bc15e30a846bb99d9df8c (patch)
tree5b75a07ff58a1ddc82a2067fc6798dffcc76a0fa
parentda56d085c4524888ba337b722168e1d10d846379 (diff)
New public API to get the information of AndroidManifest.xml
Define a public API of PackageManager to get the information of AndroidManifest.xml file for the base apk and split apks. Bug: 269149275 Bug:308860376 Test: atest CtsPackageManagerTestCases Change-Id: Ic4fdc9edbd3248d55229a56d5649dcad4d835667
-rw-r--r--core/api/current.txt1
-rw-r--r--core/java/android/app/ApplicationPackageManager.java33
-rw-r--r--core/java/android/content/pm/PackageManager.java59
3 files changed, 93 insertions, 0 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index f09036bc6162..674e2cd71504 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -12781,6 +12781,7 @@ package android.content.pm {
method public boolean isPackageSuspended();
method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String);
method public abstract boolean isSafeMode();
+ method @FlaggedApi("android.content.pm.get_package_info") @WorkerThread public <T> T parseAndroidManifest(@NonNull String, @NonNull java.util.function.Function<android.content.res.XmlResourceParser,T>) throws java.io.IOException;
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryActivityProperty(@NonNull String);
method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryApplicationProperty(@NonNull String);
method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(@NonNull android.content.Intent, int);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index ca6d8df1df12..a4c3bb824502 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -80,6 +80,8 @@ import android.content.pm.SuspendDialogInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.res.ApkAssets;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
@@ -144,6 +146,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
+import java.util.function.Function;
/** @hide */
public class ApplicationPackageManager extends PackageManager {
@@ -4024,4 +4027,34 @@ public class ApplicationPackageManager extends PackageManager {
throw e.rethrowFromSystemServer();
}
}
+
+ @Override
+ public <T> T parseAndroidManifest(@NonNull String apkFilePath,
+ @NonNull Function<XmlResourceParser, T> parserFunction) throws IOException {
+ Objects.requireNonNull(apkFilePath, "apkFilePath cannot be null");
+ Objects.requireNonNull(parserFunction, "parserFunction cannot be null");
+ try (XmlResourceParser xmlResourceParser = getAndroidManifestParser(apkFilePath)) {
+ return parserFunction.apply(xmlResourceParser);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to get the android manifest parser", e);
+ throw e;
+ }
+ }
+
+ private static XmlResourceParser getAndroidManifestParser(@NonNull String apkFilePath)
+ throws IOException {
+ ApkAssets apkAssets = null;
+ try {
+ apkAssets = ApkAssets.loadFromPath(apkFilePath);
+ return apkAssets.openXml(ApkLiteParseUtils.ANDROID_MANIFEST_FILENAME);
+ } finally {
+ if (apkAssets != null) {
+ try {
+ apkAssets.close();
+ } catch (Throwable ignored) {
+ Log.w(TAG, "Failed to close apkAssets", ignored);
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c3b3423c1a57..fe31c9dbf27d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -34,6 +34,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
+import android.annotation.WorkerThread;
import android.annotation.XmlRes;
import android.app.ActivityManager;
import android.app.ActivityThread;
@@ -96,6 +97,7 @@ import com.android.internal.util.DataClass;
import dalvik.system.VMRuntime;
import java.io.File;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.cert.Certificate;
@@ -108,6 +110,7 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Class for retrieving various kinds of information related to the application
@@ -11426,4 +11429,60 @@ public abstract class PackageManager {
throw new UnsupportedOperationException(
"unregisterPackageMonitorCallback not implemented in subclass");
}
+
+ /**
+ * Retrieve AndroidManifest.xml information for the given application apk path.
+ *
+ * <p>Example:
+ *
+ * <pre><code>
+ * Bundle result;
+ * try {
+ * result = getContext().getPackageManager().parseAndroidManifest(apkFilePath,
+ * xmlResourceParser -> {
+ * Bundle bundle = new Bundle();
+ * // Search the start tag
+ * int type;
+ * while ((type = xmlResourceParser.next()) != XmlPullParser.START_TAG
+ * &amp;&amp; type != XmlPullParser.END_DOCUMENT) {
+ * }
+ * if (type != XmlPullParser.START_TAG) {
+ * return bundle;
+ * }
+ *
+ * // Start to read the tags and attributes from the xmlResourceParser
+ * if (!xmlResourceParser.getName().equals("manifest")) {
+ * return bundle;
+ * }
+ * String packageName = xmlResourceParser.getAttributeValue(null, "package");
+ * bundle.putString("package", packageName);
+ *
+ * // Continue to read the tags and attributes from the xmlResourceParser
+ *
+ * return bundle;
+ * });
+ * } catch (IOException e) {
+ * }
+ * </code></pre>
+ *
+ * Note: When the parserFunction is invoked, the client can read the AndroidManifest.xml
+ * information by the XmlResourceParser object. After leaving the parserFunction, the
+ * XmlResourceParser object will be closed.
+ *
+ * @param apkFilePath The path of an application apk file.
+ * @param parserFunction The parserFunction will be invoked with the XmlResourceParser object
+ * after getting the AndroidManifest.xml of an application package.
+ *
+ * @return Returns the result of the {@link Function#apply(Object)}.
+ *
+ * @throws IOException if the AndroidManifest.xml of an application package cannot be
+ * read or accessed.
+ */
+ @FlaggedApi(android.content.pm.Flags.FLAG_GET_PACKAGE_INFO)
+ @WorkerThread
+ public <T> T parseAndroidManifest(@NonNull String apkFilePath,
+ @NonNull Function<XmlResourceParser, T> parserFunction) throws IOException {
+ throw new UnsupportedOperationException(
+ "parseAndroidManifest not implemented in subclass");
+ }
}