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

Commit dc8d7048 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge changes I7277880e,Ia5584bd6 into klp-dev

* changes:
  Provide calling package to ContentProviders.
  Separate root and document management.
parents a1d6a9b4 911d7f41
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -3172,6 +3172,7 @@ package android.app {
  public class AppOpsManager {
    method public int checkOp(int, int, java.lang.String);
    method public int checkOpNoThrow(int, int, java.lang.String);
    method public void checkPackage(int, java.lang.String);
    method public void finishOp(int, int, java.lang.String);
    method public void finishOp(int);
    method public int noteOp(int, int, java.lang.String);
@@ -5624,6 +5625,7 @@ package android.content {
    method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle);
    method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]);
    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    method public final java.lang.String getCallingPackage();
    method public final android.content.Context getContext();
    method public final android.content.pm.PathPermission[] getPathPermissions();
    method public final java.lang.String getReadPermission();
@@ -20747,6 +20749,7 @@ package android.provider {
    method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildDocumentUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildRecentDocumentsUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildRootUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildRootsUri(java.lang.String);
    method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
    method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
+17 −0
Original line number Diff line number Diff line
@@ -615,6 +615,23 @@ public class AppOpsManager {
        return MODE_IGNORED;
    }

    /**
     * Do a quick check to validate if a package name belongs to a UID.
     *
     * @throws SecurityException if the package name doesn't belong to the given
     *             UID, or if ownership cannot be verified.
     */
    public void checkPackage(int uid, String packageName) {
        try {
            if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
                throw new SecurityException(
                        "Package " + packageName + " does not belong to " + uid);
            }
        } catch (RemoteException e) {
            throw new SecurityException("Unable to verify package ownership", e);
        }
    }

    /**
     * Make note of an application performing an operation.  Note that you must pass
     * in both the uid and name of the application to be checked; this function will verify
+91 −25
Original line number Diff line number Diff line
@@ -102,6 +102,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    private boolean mExported;
    private boolean mNoPerms;

    private final ThreadLocal<String> mCallingPackage = new ThreadLocal<String>();

    private Transport mTransport = new Transport();

    /**
@@ -194,8 +196,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
                return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
                        CancellationSignal.fromTransport(cancellationSignal));
            }
            return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
            mCallingPackage.set(callingPkg);
            try {
                return ContentProvider.this.query(
                        uri, projection, selection, selectionArgs, sortOrder,
                        CancellationSignal.fromTransport(cancellationSignal));
            } finally {
                mCallingPackage.set(null);
            }
        }

        @Override
@@ -208,7 +216,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
            if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                return rejectInsert(uri, initialValues);
            }
            mCallingPackage.set(callingPkg);
            try {
                return ContentProvider.this.insert(uri, initialValues);
            } finally {
                mCallingPackage.set(null);
            }
        }

        @Override
@@ -216,7 +229,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
            if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                return 0;
            }
            mCallingPackage.set(callingPkg);
            try {
                return ContentProvider.this.bulkInsert(uri, initialValues);
            } finally {
                mCallingPackage.set(null);
            }
        }

        @Override
@@ -238,7 +256,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
                    }
                }
            }
            mCallingPackage.set(callingPkg);
            try {
                return ContentProvider.this.applyBatch(operations);
            } finally {
                mCallingPackage.set(null);
            }
        }

        @Override
@@ -246,7 +269,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
            if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                return 0;
            }
            mCallingPackage.set(callingPkg);
            try {
                return ContentProvider.this.delete(uri, selection, selectionArgs);
            } finally {
                mCallingPackage.set(null);
            }
        }

        @Override
@@ -255,7 +283,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
            if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                return 0;
            }
            mCallingPackage.set(callingPkg);
            try {
                return ContentProvider.this.update(uri, values, selection, selectionArgs);
            } finally {
                mCallingPackage.set(null);
            }
        }

        @Override
@@ -263,8 +296,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                throws FileNotFoundException {
            enforceFilePermission(callingPkg, uri, mode);
            mCallingPackage.set(callingPkg);
            try {
                return ContentProvider.this.openFile(
                        uri, mode, CancellationSignal.fromTransport(cancellationSignal));
            } finally {
                mCallingPackage.set(null);
            }
        }

        @Override
@@ -272,13 +310,23 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                throws FileNotFoundException {
            enforceFilePermission(callingPkg, uri, mode);
            mCallingPackage.set(callingPkg);
            try {
                return ContentProvider.this.openAssetFile(
                        uri, mode, CancellationSignal.fromTransport(cancellationSignal));
            } finally {
                mCallingPackage.set(null);
            }
        }

        @Override
        public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
            return ContentProvider.this.callFromPackage(callingPkg, method, arg, extras);
            mCallingPackage.set(callingPkg);
            try {
                return ContentProvider.this.call(method, arg, extras);
            } finally {
                mCallingPackage.set(null);
            }
        }

        @Override
@@ -290,8 +338,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
        public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
                Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
            enforceFilePermission(callingPkg, uri, "r");
            mCallingPackage.set(callingPkg);
            try {
                return ContentProvider.this.openTypedAssetFile(
                        uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
            } finally {
                mCallingPackage.set(null);
            }
        }

        @Override
@@ -460,6 +513,28 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
        return mContext;
    }

    /**
     * Return the package name of the caller that initiated the request being
     * processed on the current thread. The returned package will have been
     * verified to belong to the calling UID. Returns {@code null} if not
     * currently processing a request.
     * <p>
     * This will always return {@code null} when processing
     * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
     *
     * @see Binder#getCallingUid()
     * @see Context#grantUriPermission(String, Uri, int)
     * @throws SecurityException if the calling package doesn't belong to the
     *             calling UID.
     */
    public final String getCallingPackage() {
        final String pkg = mCallingPackage.get();
        if (pkg != null) {
            mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
        }
        return pkg;
    }

    /**
     * Change the permission required to read data from the content
     * provider.  This is normally set for you from its manifest information
@@ -529,8 +604,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
    /** @hide */
    public final void setAppOps(int readOp, int writeOp) {
        if (!mNoPerms) {
            mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService(
                    Context.APP_OPS_SERVICE);
            mTransport.mReadOp = readOp;
            mTransport.mWriteOp = writeOp;
        }
@@ -1413,6 +1486,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
         */
        if (mContext == null) {
            mContext = context;
            mTransport.mAppOpsManager = (AppOpsManager) mContext.getSystemService(
                    Context.APP_OPS_SERVICE);
            mMyUid = Process.myUid();
            if (info != null) {
                setReadPermission(info.readPermission);
@@ -1451,15 +1526,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
        return results;
    }

    /**
     * @hide
     * Front-end to {@link #call(String, String, android.os.Bundle)} that provides the name
     * of the calling package.
     */
    public Bundle callFromPackage(String callingPackag, String method, String arg, Bundle extras) {
        return call(method, arg, extras);
    }

    /**
     * Call a provider-defined method.  This can be used to implement
     * interfaces that are cheaper and/or unnatural for a table-like
+17 −1
Original line number Diff line number Diff line
@@ -72,7 +72,9 @@ public final class DocumentsContract {
    public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER";

    /** {@hide} */
    public static final String ACTION_MANAGE_DOCUMENTS = "android.provider.action.MANAGE_DOCUMENTS";
    public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT";
    /** {@hide} */
    public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT";

    /**
     * Constants related to a document, including {@link Cursor} columns names
@@ -346,6 +348,9 @@ public final class DocumentsContract {
         */
        public static final String COLUMN_MIME_TYPES = "mime_types";

        /** {@hide} */
        public static final String MIME_TYPE_ITEM = "vnd.android.document/root";

        /**
         * Type of root that represents a storage service, such as a cloud-based
         * service.
@@ -461,6 +466,17 @@ public final class DocumentsContract {
                .authority(authority).appendPath(PATH_ROOT).build();
    }

    /**
     * Build Uri representing the given {@link Root#COLUMN_ROOT_ID} in a
     * document provider.
     *
     * @see #getRootId(Uri)
     */
    public static Uri buildRootUri(String authority, String rootId) {
        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
                .authority(authority).appendPath(PATH_ROOT).appendPath(rootId).build();
    }

    /**
     * Build Uri representing the recently modified documents of a specific
     * root. When queried, a provider will return zero or more rows with columns
+23 −15
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Point;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
@@ -42,8 +41,6 @@ import android.os.ParcelFileDescriptor.OnCloseListener;
import android.provider.DocumentsContract.Document;
import android.util.Log;

import com.android.internal.util.ArrayUtils;

import libcore.io.IoUtils;

import java.io.FileNotFoundException;
@@ -75,11 +72,12 @@ import java.io.FileNotFoundException;
public abstract class DocumentsProvider extends ContentProvider {
    private static final String TAG = "DocumentsProvider";

    private static final int MATCH_ROOT = 1;
    private static final int MATCH_RECENT = 2;
    private static final int MATCH_DOCUMENT = 3;
    private static final int MATCH_CHILDREN = 4;
    private static final int MATCH_SEARCH = 5;
    private static final int MATCH_ROOTS = 1;
    private static final int MATCH_ROOT = 2;
    private static final int MATCH_RECENT = 3;
    private static final int MATCH_DOCUMENT = 4;
    private static final int MATCH_CHILDREN = 5;
    private static final int MATCH_SEARCH = 6;

    private String mAuthority;

@@ -93,7 +91,8 @@ public abstract class DocumentsProvider extends ContentProvider {
        mAuthority = info.authority;

        mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        mMatcher.addURI(mAuthority, "root", MATCH_ROOT);
        mMatcher.addURI(mAuthority, "root", MATCH_ROOTS);
        mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT);
        mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT);
        mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
        mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
@@ -256,7 +255,7 @@ public abstract class DocumentsProvider extends ContentProvider {
            String[] selectionArgs, String sortOrder) {
        try {
            switch (mMatcher.match(uri)) {
                case MATCH_ROOT:
                case MATCH_ROOTS:
                    return queryRoots(projection);
                case MATCH_RECENT:
                    return queryRecentDocuments(getRootId(uri), projection);
@@ -285,6 +284,8 @@ public abstract class DocumentsProvider extends ContentProvider {
    public final String getType(Uri uri) {
        try {
            switch (mMatcher.match(uri)) {
                case MATCH_ROOT:
                    return DocumentsContract.Root.MIME_TYPE_ITEM;
                case MATCH_DOCUMENT:
                    return getDocumentType(getDocumentId(uri));
                default:
@@ -328,15 +329,22 @@ public abstract class DocumentsProvider extends ContentProvider {
        throw new UnsupportedOperationException("Update not supported");
    }

    /** {@hide} */
    /**
     * Implementation is provided by the parent class. Can be overridden to
     * provide additional functionality, but subclasses <em>must</em> always
     * call the superclass. If the superclass returns {@code null}, the subclass
     * may implement custom behavior.
     *
     * @see #openDocument(String, String, CancellationSignal)
     * @see #deleteDocument(String)
     */
    @Override
    public final Bundle callFromPackage(
            String callingPackage, String method, String arg, Bundle extras) {
    public Bundle call(String method, String arg, Bundle extras) {
        final Context context = getContext();

        if (!method.startsWith("android:")) {
            // Let non-platform methods pass through
            return super.callFromPackage(callingPackage, method, arg, extras);
            return super.call(method, arg, extras);
        }

        final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID);
@@ -364,7 +372,7 @@ public abstract class DocumentsProvider extends ContentProvider {
                if (!callerHasManage) {
                    final Uri newDocumentUri = DocumentsContract.buildDocumentUri(
                            mAuthority, newDocumentId);
                    context.grantUriPermission(callingPackage, newDocumentUri,
                    context.grantUriPermission(getCallingPackage(), newDocumentUri,
                            Intent.FLAG_GRANT_READ_URI_PERMISSION
                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                            | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
Loading