Provide calling package to ContentProviders.

The calling package is important for ContentProviders that want to
grant Uri permissions as a side effect of operations, so offer it
through a new API.  Validates the provided package against the
calling UID before returning.

Bug: 10626527
Change-Id: I7277880eebbd48444c024bcf5f69199133cd59e4
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index b9121c7..24c396a 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -102,6 +102,8 @@
     private boolean mExported;
     private boolean mNoPerms;
 
+    private final ThreadLocal<String> mCallingPackage = new ThreadLocal<String>();
+
     private Transport mTransport = new Transport();
 
     /**
@@ -194,8 +196,14 @@
                 return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
                         CancellationSignal.fromTransport(cancellationSignal));
             }
-            return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
-                    CancellationSignal.fromTransport(cancellationSignal));
+            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 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return rejectInsert(uri, initialValues);
             }
-            return ContentProvider.this.insert(uri, initialValues);
+            mCallingPackage.set(callingPkg);
+            try {
+                return ContentProvider.this.insert(uri, initialValues);
+            } finally {
+                mCallingPackage.set(null);
+            }
         }
 
         @Override
@@ -216,7 +229,12 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
-            return ContentProvider.this.bulkInsert(uri, initialValues);
+            mCallingPackage.set(callingPkg);
+            try {
+                return ContentProvider.this.bulkInsert(uri, initialValues);
+            } finally {
+                mCallingPackage.set(null);
+            }
         }
 
         @Override
@@ -238,7 +256,12 @@
                     }
                 }
             }
-            return ContentProvider.this.applyBatch(operations);
+            mCallingPackage.set(callingPkg);
+            try {
+                return ContentProvider.this.applyBatch(operations);
+            } finally {
+                mCallingPackage.set(null);
+            }
         }
 
         @Override
@@ -246,7 +269,12 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
-            return ContentProvider.this.delete(uri, selection, selectionArgs);
+            mCallingPackage.set(callingPkg);
+            try {
+                return ContentProvider.this.delete(uri, selection, selectionArgs);
+            } finally {
+                mCallingPackage.set(null);
+            }
         }
 
         @Override
@@ -255,7 +283,12 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
-            return ContentProvider.this.update(uri, values, selection, selectionArgs);
+            mCallingPackage.set(callingPkg);
+            try {
+                return ContentProvider.this.update(uri, values, selection, selectionArgs);
+            } finally {
+                mCallingPackage.set(null);
+            }
         }
 
         @Override
@@ -263,8 +296,13 @@
                 String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, mode);
-            return ContentProvider.this.openFile(
-                    uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+            mCallingPackage.set(callingPkg);
+            try {
+                return ContentProvider.this.openFile(
+                        uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+            } finally {
+                mCallingPackage.set(null);
+            }
         }
 
         @Override
@@ -272,13 +310,23 @@
                 String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, mode);
-            return ContentProvider.this.openAssetFile(
-                    uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+            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 AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
                 Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, "r");
-            return ContentProvider.this.openTypedAssetFile(
-                    uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
+            mCallingPackage.set(callingPkg);
+            try {
+                return ContentProvider.this.openTypedAssetFile(
+                        uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
+            } finally {
+                mCallingPackage.set(null);
+            }
         }
 
         @Override
@@ -461,6 +514,28 @@
     }
 
     /**
+     * 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
      * when the provider is first created.
@@ -529,8 +604,6 @@
     /** @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 @@
          */
         if (mContext == null) {
             mContext = context;
+            mTransport.mAppOpsManager = (AppOpsManager) mContext.getSystemService(
+                    Context.APP_OPS_SERVICE);
             mMyUid = Process.myUid();
             if (info != null) {
                 setReadPermission(info.readPermission);
@@ -1452,15 +1527,6 @@
     }
 
     /**
-     * @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
      * model.