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

Commit e5290652 authored by William Loh's avatar William Loh
Browse files

Add new getAppMetadata and setAppMetadata APIs

To support Android Safety Labels, PM will store App metadata that can
be optionally provided by installers.

The PackageInstaller.Session.setAppMetadata API can be used to add app
metadata as a PersistableBundle. Due to the size of this data, it will
be written directly to file on the server via a fd.

The PackageInstaller.Session.getAppMetadata API can be used to fetch
any app metadata that may have been set.

The PackageManager.getAppMetadata system API can be used to fetch this
data as a PersistableBundle for installed apps.

Bug: 252811917
Test: atest CtsPackageInstallTestCases:android.packageinstaller.install.cts.InstallAppMetadataTest
CTS-Coverage-Bug: 262054444
Change-Id: I883e40dc4bc018875be3af096a395abe7d5ba445
parent 64037de2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -11809,6 +11809,7 @@ package android.content.pm {
    method public void close();
    method public void commit(@NonNull android.content.IntentSender);
    method public void fsync(@NonNull java.io.OutputStream) throws java.io.IOException;
    method @NonNull public android.os.PersistableBundle getAppMetadata();
    method @NonNull public int[] getChildSessionIds();
    method @NonNull public String[] getNames() throws java.io.IOException;
    method public int getParentSessionId();
@@ -11821,6 +11822,7 @@ package android.content.pm {
    method public void removeSplit(@NonNull String) throws java.io.IOException;
    method public void requestChecksums(@NonNull String, int, @NonNull java.util.List<java.security.cert.Certificate>, @NonNull java.util.concurrent.Executor, @NonNull android.content.pm.PackageManager.OnChecksumsReadyListener) throws java.security.cert.CertificateEncodingException, java.io.FileNotFoundException;
    method public void requestUserPreapproval(@NonNull android.content.pm.PackageInstaller.PreapprovalDetails, @NonNull android.content.IntentSender);
    method public void setAppMetadata(@Nullable android.os.PersistableBundle) throws java.io.IOException;
    method @Deprecated public void setChecksums(@NonNull String, @NonNull java.util.List<android.content.pm.Checksum>, @Nullable byte[]) throws java.io.IOException;
    method public void setStagingProgress(float);
    method public void transfer(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+1 −0
Original line number Diff line number Diff line
@@ -3612,6 +3612,7 @@ package android.content.pm {
    method public abstract boolean arePermissionsIndividuallyControlled();
    method @NonNull public boolean[] canPackageQuery(@NonNull String, @NonNull String[]) throws android.content.pm.PackageManager.NameNotFoundException;
    method @NonNull public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(@NonNull String);
    method @NonNull @RequiresPermission("android.permission.GET_APP_METADATA") public android.os.PersistableBundle getAppMetadata(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.pm.ApplicationInfo getApplicationInfoAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
    method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.pm.ApplicationInfo getApplicationInfoAsUser(@NonNull String, @NonNull android.content.pm.PackageManager.ApplicationInfoFlags, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
    method @NonNull public android.content.pm.dex.ArtManager getArtManager();
+32 −0
Original line number Diff line number Diff line
@@ -126,6 +126,11 @@ import dalvik.system.VMRuntime;

import libcore.util.EmptyArray;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
@@ -1223,6 +1228,33 @@ public class ApplicationPackageManager extends PackageManager {
        }
    }

    @Override
    @NonNull
    public PersistableBundle getAppMetadata(@NonNull String packageName)
            throws NameNotFoundException {
        PersistableBundle appMetadata = null;
        String path = null;
        try {
            path = mPM.getAppMetadataPath(packageName, getUserId());
        } catch (ParcelableException e) {
            e.maybeRethrow(NameNotFoundException.class);
            throw new RuntimeException(e);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        if (path != null) {
            File file = new File(path);
            try (InputStream inputStream = new FileInputStream(file)) {
                appMetadata = PersistableBundle.readFromStream(inputStream);
            } catch (FileNotFoundException e) {
                // ignore and return empty bundle if app metadata does not exist
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return appMetadata != null ? appMetadata : new PersistableBundle();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<PackageInfo> getPackagesHoldingPermissions(String[] permissions, int flags) {
+3 −0
Original line number Diff line number Diff line
@@ -63,4 +63,7 @@ interface IPackageInstallerSession {
    void requestUserPreapproval(in PackageInstaller.PreapprovalDetails details, in IntentSender statusReceiver);

    boolean isKeepApplicationEnabledSetting();

    ParcelFileDescriptor getAppMetadataFd();
    ParcelFileDescriptor openWriteAppMetadata();
}
+2 −0
Original line number Diff line number Diff line
@@ -159,6 +159,8 @@ interface IPackageManager {
     */
    ParceledListSlice getInstalledPackages(long flags, in int userId);

    String getAppMetadataPath(String packageName, int userId);

    /**
     * This implements getPackagesHoldingPermissions via a "last returned row"
     * mechanism that is not exposed in the API. This is to get around the IPC
Loading