Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 76c2c47c authored by lpeter's avatar lpeter
Browse files

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
parent da56d085
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+33 −0
Original line number Diff line number Diff line
@@ -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);
                }
            }
        }
    }
}
+59 −0
Original line number Diff line number Diff line
@@ -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");
    }
}