diff options
| -rw-r--r-- | core/api/current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 33 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageManager.java | 59 |
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 + * && 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"); + } } |