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

Commit 88ee72e4 authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Automerger Merge Worker
Browse files

Merge "Add API to allow apps with location permission to access data blobs."...

Merge "Add API to allow apps with location permission to access data blobs." into sc-dev am: 624f4c52

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13988108

Change-Id: Ied01741fd93f0be96d28eeee8e5a2b501ab89063
parents d88145e1 624f4c52
Loading
Loading
Loading
Loading
+66 −5
Original line number Diff line number Diff line
@@ -258,7 +258,8 @@ public class BlobStoreManager {
    public @NonNull ParcelFileDescriptor openBlob(@NonNull BlobHandle blobHandle)
            throws IOException {
        try {
            return mService.openBlob(blobHandle, mContext.getOpPackageName());
            return mService.openBlob(blobHandle, mContext.getOpPackageName(),
                    mContext.getAttributionTag());
        } catch (ParcelableException e) {
            e.maybeRethrow(IOException.class);
            throw new RuntimeException(e);
@@ -315,7 +316,7 @@ public class BlobStoreManager {
            @CurrentTimeMillisLong long leaseExpiryTimeMillis) throws IOException {
        try {
            mService.acquireLease(blobHandle, descriptionResId, null, leaseExpiryTimeMillis,
                    mContext.getOpPackageName());
                    mContext.getOpPackageName(), mContext.getAttributionTag());
        } catch (ParcelableException e) {
            e.maybeRethrow(IOException.class);
            e.maybeRethrow(LimitExceededException.class);
@@ -378,7 +379,7 @@ public class BlobStoreManager {
            @CurrentTimeMillisLong long leaseExpiryTimeMillis) throws IOException {
        try {
            mService.acquireLease(blobHandle, INVALID_RES_ID, description, leaseExpiryTimeMillis,
                    mContext.getOpPackageName());
                    mContext.getOpPackageName(), mContext.getAttributionTag());
        } catch (ParcelableException e) {
            e.maybeRethrow(IOException.class);
            e.maybeRethrow(LimitExceededException.class);
@@ -497,7 +498,8 @@ public class BlobStoreManager {
     */
    public void releaseLease(@NonNull BlobHandle blobHandle) throws IOException {
        try {
            mService.releaseLease(blobHandle, mContext.getOpPackageName());
            mService.releaseLease(blobHandle, mContext.getOpPackageName(),
                    mContext.getAttributionTag());
        } catch (ParcelableException e) {
            e.maybeRethrow(IOException.class);
            throw new RuntimeException(e);
@@ -602,7 +604,8 @@ public class BlobStoreManager {
    @Nullable
    public LeaseInfo getLeaseInfo(@NonNull BlobHandle blobHandle) throws IOException {
        try {
            return mService.getLeaseInfo(blobHandle, mContext.getOpPackageName());
            return mService.getLeaseInfo(blobHandle, mContext.getOpPackageName(),
                    mContext.getAttributionTag());
        } catch (ParcelableException e) {
            e.maybeRethrow(IOException.class);
            throw new RuntimeException(e);
@@ -896,6 +899,64 @@ public class BlobStoreManager {
            }
        }

        /**
         * Allow apps with location permission to access this blob data once it is committed using
         * a {@link BlobHandle} representing the blob.
         *
         * <p> This needs to be called before committing the blob using
         * {@link #commit(Executor, Consumer)}.
         *
         * Note that if a caller allows access to the blob using this API in addition to other APIs
         * like {@link #allowPackageAccess(String, byte[])}, then apps satisfying any one of these
         * access conditions will be allowed to access the blob.
         *
         * @param permissionName the name of the location permission that needs to be granted
         *                       for the app. This can be either one of
         *                       {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
         *                       {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
         *
         * @throws IOException when there is an I/O error while changing the access.
         * @throws SecurityException when the caller is not the owner of the session.
         * @throws IllegalStateException when the caller tries to change access for a blob which is
         *                               already committed.
         */
        public void allowPackagesWithLocationPermission(@NonNull String permissionName)
                throws IOException {
            try {
                mSession.allowPackagesWithLocationPermission(permissionName);
            } catch (ParcelableException e) {
                e.maybeRethrow(IOException.class);
                throw new RuntimeException(e);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        /**
         * Returns {@code true} if access has been allowed for apps with location permission by
         * using {@link #allowPackagesWithLocationPermission(String)}.
         *
         * @param permissionName the name of the location permission that needs to be granted
         *                       for the app. This can be either one of
         *                       {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
         *                       {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
         *
         * @throws IOException when there is an I/O error while getting the access type.
         * @throws IllegalStateException when the caller tries to get access type from a session
         *                               which is closed or abandoned.
         */
        public boolean arePackagesWithLocationPermissionAllowed(@NonNull String permissionName)
                throws IOException {
            try {
                return mSession.arePackagesWithLocationPermissionAllowed(permissionName);
            } catch (ParcelableException e) {
                e.maybeRethrow(IOException.class);
                throw new RuntimeException(e);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        /**
         * Commit the file that was written so far to this session to the blob store maintained by
         * the system.
+6 −4
Original line number Diff line number Diff line
@@ -25,12 +25,13 @@ import android.os.RemoteCallback;
interface IBlobStoreManager {
    long createSession(in BlobHandle handle, in String packageName);
    IBlobStoreSession openSession(long sessionId, in String packageName);
    ParcelFileDescriptor openBlob(in BlobHandle handle, in String packageName);
    ParcelFileDescriptor openBlob(in BlobHandle handle, in String packageName,
           in String attributionTag);
    void abandonSession(long sessionId, in String packageName);

    void acquireLease(in BlobHandle handle, int descriptionResId, in CharSequence description,
            long leaseTimeoutMillis, in String packageName);
    void releaseLease(in BlobHandle handle, in String packageName);
            long leaseTimeoutMillis, in String packageName, in String attributionTag);
    void releaseLease(in BlobHandle handle, in String packageName, in String attributionTag);
    long getRemainingLeaseQuotaBytes(String packageName);

    void waitForIdle(in RemoteCallback callback);
@@ -39,5 +40,6 @@ interface IBlobStoreManager {
    void deleteBlob(long blobId);

    List<BlobHandle> getLeasedBlobs(in String packageName);
    LeaseInfo getLeaseInfo(in BlobHandle blobHandle, in String packageName);
    LeaseInfo getLeaseInfo(in BlobHandle blobHandle, in String packageName,
            in String attributionTag);
}
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
@@ -26,10 +26,12 @@ interface IBlobStoreSession {
    void allowPackageAccess(in String packageName, in byte[] certificate);
    void allowSameSignatureAccess();
    void allowPublicAccess();
    void allowPackagesWithLocationPermission(in String permissionName);

    boolean isPackageAccessAllowed(in String packageName, in byte[] certificate);
    boolean isSameSignatureAccessAllowed();
    boolean isPublicAccessAllowed();
    boolean arePackagesWithLocationPermissionAllowed(in String permissionName);

    long getSize();
    void close();
+4 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ public final class XmlTags {
    public static final String ATTR_TYPE = "t";
    public static final String TAG_ALLOWED_PACKAGE = "wl";
    public static final String ATTR_CERTIFICATE = "ct";
    public static final String TAG_ALLOWED_PERMISSION = "ap";

    // For BlobHandle
    public static final String TAG_BLOB_HANDLE = "bh";
@@ -55,4 +56,7 @@ public final class XmlTags {
    public static final String TAG_LEASEE = "l";
    public static final String ATTR_DESCRIPTION_RES_NAME = "rn";
    public static final String ATTR_DESCRIPTION = "d";

    // Generic
    public static final String ATTR_VALUE = "val";
}
+79 −2
Original line number Diff line number Diff line
@@ -15,18 +15,29 @@
 */
package com.android.server.blob;

import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.app.blob.XmlTags.ATTR_CERTIFICATE;
import static android.app.blob.XmlTags.ATTR_PACKAGE;
import static android.app.blob.XmlTags.ATTR_TYPE;
import static android.app.blob.XmlTags.ATTR_VALUE;
import static android.app.blob.XmlTags.TAG_ALLOWED_PACKAGE;
import static android.app.blob.XmlTags.TAG_ALLOWED_PERMISSION;

import static com.android.server.blob.BlobStoreConfig.TAG;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.permission.PermissionManager;
import android.util.ArraySet;
import android.util.Base64;
import android.util.DebugUtils;
import android.util.Slog;

import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
@@ -53,21 +64,27 @@ class BlobAccessMode {
            ACCESS_TYPE_PUBLIC,
            ACCESS_TYPE_SAME_SIGNATURE,
            ACCESS_TYPE_ALLOWLIST,
            ACCESS_TYPE_LOCATION_PERMISSION,
    })
    @interface AccessType {}
    public static final int ACCESS_TYPE_PRIVATE = 1 << 0;
    public static final int ACCESS_TYPE_PUBLIC = 1 << 1;
    public static final int ACCESS_TYPE_SAME_SIGNATURE = 1 << 2;
    public static final int ACCESS_TYPE_ALLOWLIST = 1 << 3;
    public static final int ACCESS_TYPE_LOCATION_PERMISSION = 1 << 4;

    private int mAccessType = ACCESS_TYPE_PRIVATE;

    private final ArraySet<PackageIdentifier> mAllowedPackages = new ArraySet<>();
    private final ArraySet<String> mAllowedPermissions = new ArraySet<>();

    void allow(BlobAccessMode other) {
        if ((other.mAccessType & ACCESS_TYPE_ALLOWLIST) != 0) {
            mAllowedPackages.addAll(other.mAllowedPackages);
        }
        if ((other.mAccessType & ACCESS_TYPE_LOCATION_PERMISSION) != 0) {
            mAllowedPermissions.addAll(other.mAllowedPermissions);
        }
        mAccessType |= other.mAccessType;
    }

@@ -84,6 +101,11 @@ class BlobAccessMode {
        mAllowedPackages.add(PackageIdentifier.create(packageName, certificate));
    }

    void allowPackagesWithLocationPermission(@NonNull String permissionName) {
        mAccessType |= ACCESS_TYPE_LOCATION_PERMISSION;
        mAllowedPermissions.add(permissionName);
    }

    boolean isPublicAccessAllowed() {
        return (mAccessType & ACCESS_TYPE_PUBLIC) != 0;
    }
@@ -99,8 +121,15 @@ class BlobAccessMode {
        return mAllowedPackages.contains(PackageIdentifier.create(packageName, certificate));
    }

    boolean isAccessAllowedForCaller(Context context,
            @NonNull String callingPackage, @NonNull String committerPackage) {
    boolean arePackagesWithLocationPermissionAllowed(@NonNull String permissionName) {
        if ((mAccessType & ACCESS_TYPE_LOCATION_PERMISSION) == 0) {
            return false;
        }
        return mAllowedPermissions.contains(permissionName);
    }

    boolean isAccessAllowedForCaller(Context context, @NonNull String callingPackage,
            @NonNull String committerPackage, int callingUid, @Nullable String attributionTag) {
        if ((mAccessType & ACCESS_TYPE_PUBLIC) != 0) {
            return true;
        }
@@ -124,9 +153,37 @@ class BlobAccessMode {
            }
        }

        if ((mAccessType & ACCESS_TYPE_LOCATION_PERMISSION) != 0) {
            final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
            for (int i = 0; i < mAllowedPermissions.size(); ++i) {
                final String permission = mAllowedPermissions.valueAt(i);
                if (PermissionManager.checkPackageNamePermission(permission, callingPackage,
                        UserHandle.getUserId(callingUid)) != PackageManager.PERMISSION_GRANTED) {
                    continue;
                }
                // TODO: Add appropriate message
                if (appOpsManager.noteOpNoThrow(getAppOp(permission), callingUid, callingPackage,
                        attributionTag, null /* message */) == AppOpsManager.MODE_ALLOWED) {
                    return true;
                }
            }
        }

        return false;
    }

    private static String getAppOp(String permission) {
        switch (permission) {
            case ACCESS_FINE_LOCATION:
                return AppOpsManager.OPSTR_FINE_LOCATION;
            case ACCESS_COARSE_LOCATION:
                return AppOpsManager.OPSTR_COARSE_LOCATION;
            default:
                Slog.w(TAG, "Unknown permission found: " + permission);
                return null;
        }
    }

    int getAccessType() {
        return mAccessType;
    }
@@ -148,6 +205,16 @@ class BlobAccessMode {
            }
            fout.decreaseIndent();
        }
        fout.print("Allowed permissions:");
        if (mAllowedPermissions.isEmpty()) {
            fout.println(" (Empty)");
        } else {
            fout.increaseIndent();
            for (int i = 0, count = mAllowedPermissions.size(); i < count; ++i) {
                fout.println(mAllowedPermissions.valueAt(i).toString());
            }
            fout.decreaseIndent();
        }
    }

    void writeToXml(@NonNull XmlSerializer out) throws IOException {
@@ -159,6 +226,12 @@ class BlobAccessMode {
            XmlUtils.writeByteArrayAttribute(out, ATTR_CERTIFICATE, packageIdentifier.certificate);
            out.endTag(null, TAG_ALLOWED_PACKAGE);
        }
        for (int i = 0, count = mAllowedPermissions.size(); i < count; ++i) {
            out.startTag(null, TAG_ALLOWED_PERMISSION);
            final String permission = mAllowedPermissions.valueAt(i);
            XmlUtils.writeStringAttribute(out, ATTR_VALUE, permission);
            out.endTag(null, TAG_ALLOWED_PERMISSION);
        }
    }

    @NonNull
@@ -176,6 +249,10 @@ class BlobAccessMode {
                final byte[] certificate = XmlUtils.readByteArrayAttribute(in, ATTR_CERTIFICATE);
                blobAccessMode.allowPackageAccess(packageName, certificate);
            }
            if (TAG_ALLOWED_PERMISSION.equals(in.getName())) {
                final String permission = XmlUtils.readStringAttribute(in, ATTR_VALUE);
                blobAccessMode.allowPackagesWithLocationPermission(permission);
            }
        }
        return blobAccessMode;
    }
Loading