OSDN Git Service

Note with featureId from ContentProvider
authorPhilip P. Moltmann <moltmann@google.com>
Fri, 27 Sep 2019 15:44:12 +0000 (08:44 -0700)
committerPhilip P. Moltmann <moltmann@google.com>
Tue, 29 Oct 2019 22:41:28 +0000 (15:41 -0700)
This takes the Context#getFeatureId from the calling context and pipes
it all way through to the noteOp calls done by the content provider.

Bug: 136595429
Test: atest CtsAppOpsTestCases (new test added to capture this case)
            TelecomUnitTests:CallLogManagerTest
    ContentProviderClientTest
    TelecomUnitTests:MissedCallNotifierImplTest
    TelecomUnitTests:BasicCallTests
    MediaInserterTest
    PreferencesHelperTest
    RankingHelperTest
    PinnedSliceStateTest
    FrameworksCoreTests:ContentResolverTest
Change-Id: I53b1035626229c920b353509a5bece157b52fb51

24 files changed:
api/current.txt
cmds/content/src/com/android/commands/content/Content.java
cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
core/java/android/content/ContentProvider.java
core/java/android/content/ContentProviderClient.java
core/java/android/content/ContentProviderNative.java
core/java/android/content/ContentResolver.java
core/java/android/content/IContentProvider.java
core/java/android/provider/DocumentsProvider.java
core/java/android/provider/Settings.java
core/tests/coretests/src/android/content/ContentResolverTest.java
core/tests/coretests/src/android/provider/TestDocumentsProvider.java
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
test-mock/src/android/test/mock/MockContentProvider.java
test-mock/src/android/test/mock/MockIContentProvider.java

index 57bbd77..bec1bc8 100644 (file)
@@ -9467,6 +9467,7 @@ package android.content {
     method @NonNull public final android.content.ContentProvider.CallingIdentity clearCallingIdentity();
     method public abstract int delete(@NonNull android.net.Uri, @Nullable String, @Nullable String[]);
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method @Nullable public final String getCallingFeatureId();
     method @Nullable public final String getCallingPackage();
     method @Nullable public final android.content.Context getContext();
     method @Nullable public final android.content.pm.PathPermission[] getPathPermissions();
index 55dbc17..7e278e9 100644 (file)
@@ -508,7 +508,7 @@ public class Content {
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.insert(resolveCallingPackage(), mUri, mContentValues);
+            provider.insert(resolveCallingPackage(), null, mUri, mContentValues);
         }
     }
 
@@ -522,7 +522,7 @@ public class Content {
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.delete(resolveCallingPackage(), mUri, mWhere, null);
+            provider.delete(resolveCallingPackage(), null, mUri, mWhere, null);
         }
     }
 
@@ -557,7 +557,7 @@ public class Content {
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            Bundle result = provider.call(null, mUri.getAuthority(), mMethod, mArg, mExtras);
+            Bundle result = provider.call(null, null, mUri.getAuthority(), mMethod, mArg, mExtras);
             if (result != null) {
                 result.size(); // unpack
             }
@@ -584,7 +584,7 @@ public class Content {
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            try (ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null, null)) {
+            try (ParcelFileDescriptor fd = provider.openFile(null, null, mUri, "r", null, null)) {
                 FileUtils.copy(fd.getFileDescriptor(), FileDescriptor.out);
             }
         }
@@ -597,7 +597,7 @@ public class Content {
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            try (ParcelFileDescriptor fd = provider.openFile(null, mUri, "w", null, null)) {
+            try (ParcelFileDescriptor fd = provider.openFile(null, null, mUri, "w", null, null)) {
                 FileUtils.copy(FileDescriptor.in, fd.getFileDescriptor());
             }
         }
@@ -616,7 +616,7 @@ public class Content {
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            Cursor cursor = provider.query(resolveCallingPackage(), mUri, mProjection,
+            Cursor cursor = provider.query(resolveCallingPackage(), null, mUri, mProjection,
                     ContentResolver.createSqlQueryBundle(mWhere, null, mSortOrder), null);
             if (cursor == null) {
                 System.out.println("No result found.");
@@ -679,7 +679,7 @@ public class Content {
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.update(resolveCallingPackage(), mUri, mContentValues, mWhere, null);
+            provider.update(resolveCallingPackage(), null, mUri, mContentValues, mWhere, null);
         }
     }
 
index 455e4bb..b23bf5d 100644 (file)
@@ -67,7 +67,7 @@ public class ShellUiAutomatorBridge extends UiAutomatorBridge {
                     throw new IllegalStateException("Could not find provider: " + providerName);
                 }
                 provider = holder.provider;
-                cursor = provider.query(null, Settings.Secure.CONTENT_URI,
+                cursor = provider.query(null, null, Settings.Secure.CONTENT_URI,
                         new String[] {
                             Settings.Secure.VALUE
                         },
index 7de8793..17f1a07 100644 (file)
@@ -53,6 +53,7 @@ import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -136,7 +137,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
     private boolean mNoPerms;
     private boolean mSingleUser;
 
-    private ThreadLocal<String> mCallingPackage;
+    private ThreadLocal<Pair<String, String>> mCallingPackage;
 
     private Transport mTransport = new Transport();
 
@@ -226,11 +227,13 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
-                @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
+        public Cursor query(String callingPkg, @Nullable String featureId, Uri uri,
+                @Nullable String[] projection, @Nullable Bundle queryArgs,
+                @Nullable ICancellationSignal cancellationSignal) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 // The caller has no access to the data, so return an empty cursor with
                 // the columns in the requested order. The caller may ask for an invalid
                 // column and we would not catch that but this is not a problem in practice.
@@ -246,7 +249,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
                 // we have to execute the query as if allowed to get a cursor with the
                 // columns. We then use the column names to return an empty cursor.
                 Cursor cursor;
-                final String original = setCallingPackage(callingPkg);
+                final Pair<String, String> original = setCallingPackage(
+                        new Pair<>(callingPkg, featureId));
                 try {
                     cursor = mInterface.query(
                             uri, projection, queryArgs,
@@ -264,7 +268,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
                 return new MatrixCursor(cursor.getColumnNames(), 0);
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "query");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.query(
                         uri, projection, queryArgs,
@@ -293,12 +298,15 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
+        public Uri insert(String callingPkg, @Nullable String featureId, Uri uri,
+                ContentValues initialValues) {
             uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
-                final String original = setCallingPackage(callingPkg);
+            if (enforceWritePermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
+                final Pair<String, String> original = setCallingPackage(
+                        new Pair<>(callingPkg, featureId));
                 try {
                     return rejectInsert(uri, initialValues);
                 } finally {
@@ -306,7 +314,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
                 }
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "insert");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return maybeAddUserId(mInterface.insert(uri, initialValues), userId);
             } catch (RemoteException e) {
@@ -318,14 +327,17 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
+        public int bulkInsert(String callingPkg, @Nullable String featureId, Uri uri,
+                ContentValues[] initialValues) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceWritePermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "bulkInsert");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.bulkInsert(uri, initialValues);
             } catch (RemoteException e) {
@@ -337,8 +349,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public ContentProviderResult[] applyBatch(String callingPkg, String authority,
-                ArrayList<ContentProviderOperation> operations)
+        public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String featureId,
+                String authority, ArrayList<ContentProviderOperation> operations)
                 throws OperationApplicationException {
             validateIncomingAuthority(authority);
             int numOperations = operations.size();
@@ -355,20 +367,21 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
                     operations.set(i, operation);
                 }
                 if (operation.isReadOperation()) {
-                    if (enforceReadPermission(callingPkg, uri, null)
+                    if (enforceReadPermission(callingPkg, featureId, uri, null)
                             != AppOpsManager.MODE_ALLOWED) {
                         throw new OperationApplicationException("App op not allowed", 0);
                     }
                 }
                 if (operation.isWriteOperation()) {
-                    if (enforceWritePermission(callingPkg, uri, null)
+                    if (enforceWritePermission(callingPkg, featureId, uri, null)
                             != AppOpsManager.MODE_ALLOWED) {
                         throw new OperationApplicationException("App op not allowed", 0);
                     }
                 }
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "applyBatch");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 ContentProviderResult[] results = mInterface.applyBatch(authority,
                         operations);
@@ -390,14 +403,17 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
+        public int delete(String callingPkg, @Nullable String featureId, Uri uri, String selection,
+                String[] selectionArgs) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceWritePermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "delete");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.delete(uri, selection, selectionArgs);
             } catch (RemoteException e) {
@@ -409,15 +425,17 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public int update(String callingPkg, Uri uri, ContentValues values, String selection,
-                String[] selectionArgs) {
+        public int update(String callingPkg, @Nullable String featureId, Uri uri,
+                ContentValues values, String selection, String[] selectionArgs) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceWritePermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "update");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.update(uri, values, selection, selectionArgs);
             } catch (RemoteException e) {
@@ -429,14 +447,15 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public ParcelFileDescriptor openFile(
-                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal,
-                IBinder callerToken) throws FileNotFoundException {
+        public ParcelFileDescriptor openFile(String callingPkg, @Nullable String featureId,
+                Uri uri, String mode, ICancellationSignal cancellationSignal, IBinder callerToken)
+                throws FileNotFoundException {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, uri, mode, callerToken);
+            enforceFilePermission(callingPkg, featureId, uri, mode, callerToken);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openFile");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.openFile(
                         uri, mode, CancellationSignal.fromTransport(cancellationSignal));
@@ -449,14 +468,15 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public AssetFileDescriptor openAssetFile(
-                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
+        public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String featureId,
+                Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, uri, mode, null);
+            enforceFilePermission(callingPkg, featureId, uri, mode, null);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openAssetFile");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.openAssetFile(
                         uri, mode, CancellationSignal.fromTransport(cancellationSignal));
@@ -469,12 +489,13 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public Bundle call(String callingPkg, String authority, String method, @Nullable String arg,
-                @Nullable Bundle extras) {
+        public Bundle call(String callingPkg, @Nullable String featureId, String authority,
+                String method, @Nullable String arg, @Nullable Bundle extras) {
             validateIncomingAuthority(authority);
             Bundle.setDefusable(extras, true);
             Trace.traceBegin(TRACE_TAG_DATABASE, "call");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.call(authority, method, arg, extras);
             } catch (RemoteException e) {
@@ -501,14 +522,16 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
-                Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
+        public AssetFileDescriptor openTypedAssetFile(String callingPkg,
+                @Nullable String featureId, Uri uri, String mimeType, Bundle opts,
+                ICancellationSignal cancellationSignal) throws FileNotFoundException {
             Bundle.setDefusable(opts, true);
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, uri, "r", null);
+            enforceFilePermission(callingPkg, featureId, uri, "r", null);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.openTypedAssetFile(
                         uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
@@ -526,15 +549,17 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public Uri canonicalize(String callingPkg, Uri uri) {
+        public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri) {
             uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return null;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "canonicalize");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return maybeAddUserId(mInterface.canonicalize(uri), userId);
             } catch (RemoteException e) {
@@ -546,15 +571,17 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public Uri uncanonicalize(String callingPkg, Uri uri) {
+        public Uri uncanonicalize(String callingPkg, String featureId,  Uri uri) {
             uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return null;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "uncanonicalize");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return maybeAddUserId(mInterface.uncanonicalize(uri), userId);
             } catch (RemoteException e) {
@@ -566,15 +593,17 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public boolean refresh(String callingPkg, Uri uri, Bundle args,
+        public boolean refresh(String callingPkg, String featureId, Uri uri, Bundle args,
                 ICancellationSignal cancellationSignal) throws RemoteException {
             uri = validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return false;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "refresh");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.refresh(uri, args,
                         CancellationSignal.fromTransport(cancellationSignal));
@@ -585,11 +614,13 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         }
 
         @Override
-        public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags) {
+        public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri,
+                int uid, int modeFlags) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             Trace.traceBegin(TRACE_TAG_DATABASE, "checkUriPermission");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.checkUriPermission(uri, uid, modeFlags);
             } catch (RemoteException e) {
@@ -600,44 +631,47 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
             }
         }
 
-        private void enforceFilePermission(String callingPkg, Uri uri, String mode,
-                IBinder callerToken) throws FileNotFoundException, SecurityException {
+        private void enforceFilePermission(String callingPkg, @Nullable String featureId, Uri uri,
+                String mode, IBinder callerToken) throws FileNotFoundException, SecurityException {
             if (mode != null && mode.indexOf('w') != -1) {
-                if (enforceWritePermission(callingPkg, uri, callerToken)
+                if (enforceWritePermission(callingPkg, featureId, uri, callerToken)
                         != AppOpsManager.MODE_ALLOWED) {
                     throw new FileNotFoundException("App op not allowed");
                 }
             } else {
-                if (enforceReadPermission(callingPkg, uri, callerToken)
+                if (enforceReadPermission(callingPkg, featureId, uri, callerToken)
                         != AppOpsManager.MODE_ALLOWED) {
                     throw new FileNotFoundException("App op not allowed");
                 }
             }
         }
 
-        private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken)
+        private int enforceReadPermission(String callingPkg, @Nullable String featureId, Uri uri,
+                IBinder callerToken)
                 throws SecurityException {
-            final int mode = enforceReadPermissionInner(uri, callingPkg, callerToken);
+            final int mode = enforceReadPermissionInner(uri, callingPkg, featureId, callerToken);
             if (mode != MODE_ALLOWED) {
                 return mode;
             }
 
-            return noteProxyOp(callingPkg, mReadOp);
+            return noteProxyOp(callingPkg, featureId, mReadOp);
         }
 
-        private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken)
+        private int enforceWritePermission(String callingPkg, String featureId, Uri uri,
+                IBinder callerToken)
                 throws SecurityException {
-            final int mode = enforceWritePermissionInner(uri, callingPkg, callerToken);
+            final int mode = enforceWritePermissionInner(uri, callingPkg, featureId, callerToken);
             if (mode != MODE_ALLOWED) {
                 return mode;
             }
 
-            return noteProxyOp(callingPkg, mWriteOp);
+            return noteProxyOp(callingPkg, featureId, mWriteOp);
         }
 
-        private int noteProxyOp(String callingPkg, int op) {
+        private int noteProxyOp(String callingPkg, String featureId, int op) {
             if (op != AppOpsManager.OP_NONE) {
-                int mode = mAppOpsManager.noteProxyOp(op, callingPkg);
+                int mode = mAppOpsManager.noteProxyOp(op, callingPkg, Binder.getCallingUid(),
+                        featureId, null);
                 return mode == MODE_DEFAULT ? MODE_IGNORED : mode;
             }
 
@@ -659,18 +693,19 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
      * associated with that permission.
      */
     private int checkPermissionAndAppOp(String permission, String callingPkg,
-            IBinder callerToken) {
+            @Nullable String featureId, IBinder callerToken) {
         if (getContext().checkPermission(permission, Binder.getCallingPid(), Binder.getCallingUid(),
                 callerToken) != PERMISSION_GRANTED) {
             return MODE_ERRORED;
         }
 
-        return mTransport.noteProxyOp(callingPkg, AppOpsManager.permissionToOpCode(permission));
+        return mTransport.noteProxyOp(callingPkg, featureId,
+                AppOpsManager.permissionToOpCode(permission));
     }
 
     /** {@hide} */
-    protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken)
-            throws SecurityException {
+    protected int enforceReadPermissionInner(Uri uri, String callingPkg,
+            @Nullable String featureId, IBinder callerToken) throws SecurityException {
         final Context context = getContext();
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -684,7 +719,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         if (mExported && checkUser(pid, uid, context)) {
             final String componentPerm = getReadPermission();
             if (componentPerm != null) {
-                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken);
+                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, featureId,
+                        callerToken);
                 if (mode == MODE_ALLOWED) {
                     return MODE_ALLOWED;
                 } else {
@@ -703,7 +739,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
                 for (PathPermission pp : pps) {
                     final String pathPerm = pp.getReadPermission();
                     if (pathPerm != null && pp.match(path)) {
-                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken);
+                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, featureId,
+                                callerToken);
                         if (mode == MODE_ALLOWED) {
                             return MODE_ALLOWED;
                         } else {
@@ -751,8 +788,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
     }
 
     /** {@hide} */
-    protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken)
-            throws SecurityException {
+    protected int enforceWritePermissionInner(Uri uri, String callingPkg,
+            @Nullable String featureId, IBinder callerToken) throws SecurityException {
         final Context context = getContext();
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -766,7 +803,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         if (mExported && checkUser(pid, uid, context)) {
             final String componentPerm = getWritePermission();
             if (componentPerm != null) {
-                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken);
+                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, featureId,
+                        callerToken);
                 if (mode == MODE_ALLOWED) {
                     return MODE_ALLOWED;
                 } else {
@@ -785,7 +823,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
                 for (PathPermission pp : pps) {
                     final String pathPerm = pp.getWritePermission();
                     if (pathPerm != null && pp.match(path)) {
-                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken);
+                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, featureId,
+                                callerToken);
                         if (mode == MODE_ALLOWED) {
                             return MODE_ALLOWED;
                         } else {
@@ -851,11 +890,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
     }
 
     /**
-     * Set the calling package, returning the current value (or {@code null})
+     * Set the calling package/feature, returning the current value (or {@code null})
      * which can be used later to restore the previous state.
      */
-    private String setCallingPackage(String callingPackage) {
-        final String original = mCallingPackage.get();
+    private Pair<String, String> setCallingPackage(Pair<String, String> callingPackage) {
+        final Pair<String, String> original = mCallingPackage.get();
         mCallingPackage.set(callingPackage);
         onCallingPackageChanged();
         return original;
@@ -876,16 +915,42 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
      *             calling UID.
      */
     public final @Nullable String getCallingPackage() {
-        final String pkg = mCallingPackage.get();
+        final Pair<String, String> pkg = mCallingPackage.get();
         if (pkg != null) {
-            mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
+            mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg.first);
+            return pkg.first;
         }
-        return pkg;
+
+        return null;
+    }
+
+    /**
+     * Return the feature in the package of the caller that initiated the request being
+     * processed on the current thread. Returns {@code null} if not currently processing
+     * a request of the request is for the default feature.
+     * <p>
+     * This will always return {@code null} when processing
+     * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
+     *
+     * @see #getCallingPackage
+     */
+    public final @Nullable String getCallingFeatureId() {
+        final Pair<String, String> pkg = mCallingPackage.get();
+        if (pkg != null) {
+            return pkg.second;
+        }
+
+        return null;
     }
 
     /** {@hide} */
     public final @Nullable String getCallingPackageUnchecked() {
-        return mCallingPackage.get();
+        final Pair<String, String> pkg = mCallingPackage.get();
+        if (pkg != null) {
+            return pkg.first;
+        }
+
+        return null;
     }
 
     /** {@hide} */
@@ -899,10 +964,10 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
         /** {@hide} */
         public final long binderToken;
         /** {@hide} */
-        public final String callingPackage;
+        public final Pair<String, String> callingPackage;
 
         /** {@hide} */
-        public CallingIdentity(long binderToken, String callingPackage) {
+        public CallingIdentity(long binderToken, Pair<String, String> callingPackage) {
             this.binderToken = binderToken;
             this.callingPackage = callingPackage;
         }
index 8a4330e..d2632e7 100644 (file)
@@ -80,6 +80,7 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
     private final IContentProvider mContentProvider;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mPackageName;
+    private final @Nullable String mFeatureId;
     private final String mAuthority;
     private final boolean mStable;
 
@@ -103,6 +104,7 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
         mContentResolver = contentResolver;
         mContentProvider = contentProvider;
         mPackageName = contentResolver.mPackageName;
+        mFeatureId = contentResolver.mFeatureId;
 
         mAuthority = authority;
         mStable = stable;
@@ -193,7 +195,7 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
             final Cursor cursor = mContentProvider.query(
-                    mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
+                    mPackageName, mFeatureId, uri, projection, queryArgs, remoteCancellationSignal);
             if (cursor == null) {
                 return null;
             }
@@ -253,7 +255,7 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
 
         beforeRemote();
         try {
-            return mContentProvider.canonicalize(mPackageName, url);
+            return mContentProvider.canonicalize(mPackageName, mFeatureId, url);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -271,7 +273,7 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
 
         beforeRemote();
         try {
-            return mContentProvider.uncanonicalize(mPackageName, url);
+            return mContentProvider.uncanonicalize(mPackageName, mFeatureId, url);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -296,7 +298,8 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
                 remoteCancellationSignal = mContentProvider.createCancellationSignal();
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
-            return mContentProvider.refresh(mPackageName, url, args, remoteCancellationSignal);
+            return mContentProvider.refresh(mPackageName, mFeatureId, url, args,
+                    remoteCancellationSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -315,7 +318,8 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
 
         beforeRemote();
         try {
-            return mContentProvider.checkUriPermission(mPackageName, uri, uid, modeFlags);
+            return mContentProvider.checkUriPermission(mPackageName, mFeatureId, uri, uid,
+                    modeFlags);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -334,7 +338,7 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
 
         beforeRemote();
         try {
-            return mContentProvider.insert(mPackageName, url, initialValues);
+            return mContentProvider.insert(mPackageName, mFeatureId, url, initialValues);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -354,7 +358,7 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
 
         beforeRemote();
         try {
-            return mContentProvider.bulkInsert(mPackageName, url, initialValues);
+            return mContentProvider.bulkInsert(mPackageName, mFeatureId, url, initialValues);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -373,7 +377,8 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
 
         beforeRemote();
         try {
-            return mContentProvider.delete(mPackageName, url, selection, selectionArgs);
+            return mContentProvider.delete(mPackageName, mFeatureId, url, selection,
+                    selectionArgs);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -392,7 +397,8 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
 
         beforeRemote();
         try {
-            return mContentProvider.update(mPackageName, url, values, selection, selectionArgs);
+            return mContentProvider.update(mPackageName, mFeatureId, url, values, selection,
+                    selectionArgs);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -436,7 +442,8 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
                 remoteSignal = mContentProvider.createCancellationSignal();
                 signal.setRemote(remoteSignal);
             }
-            return mContentProvider.openFile(mPackageName, url, mode, remoteSignal, null);
+            return mContentProvider.openFile(mPackageName, mFeatureId, url, mode, remoteSignal,
+                    null);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -480,7 +487,8 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
                 remoteSignal = mContentProvider.createCancellationSignal();
                 signal.setRemote(remoteSignal);
             }
-            return mContentProvider.openAssetFile(mPackageName, url, mode, remoteSignal);
+            return mContentProvider.openAssetFile(mPackageName, mFeatureId, url, mode,
+                    remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -521,7 +529,7 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
                 signal.setRemote(remoteSignal);
             }
             return mContentProvider.openTypedAssetFile(
-                    mPackageName, uri, mimeTypeFilter, opts, remoteSignal);
+                    mPackageName, mFeatureId, uri, mimeTypeFilter, opts, remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -548,7 +556,7 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
 
         beforeRemote();
         try {
-            return mContentProvider.applyBatch(mPackageName, authority, operations);
+            return mContentProvider.applyBatch(mPackageName, mFeatureId, authority, operations);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -574,7 +582,7 @@ public class ContentProviderClient implements ContentInterface, AutoCloseable {
 
         beforeRemote();
         try {
-            return mContentProvider.call(mPackageName, authority, method, arg, extras);
+            return mContentProvider.call(mPackageName, mFeatureId, authority, method, arg, extras);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
index cd735d4..f082690 100644 (file)
@@ -83,6 +83,7 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                     data.enforceInterface(IContentProvider.descriptor);
 
                     String callingPkg = data.readString();
+                    String callingFeatureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
 
                     // String[] projection
@@ -101,7 +102,8 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                     ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
                             data.readStrongBinder());
 
-                    Cursor cursor = query(callingPkg, url, projection, queryArgs, cancellationSignal);
+                    Cursor cursor = query(callingPkg, callingFeatureId, url, projection, queryArgs,
+                            cancellationSignal);
                     if (cursor != null) {
                         CursorToBulkCursorAdaptor adaptor = null;
 
@@ -148,10 +150,11 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     ContentValues values = ContentValues.CREATOR.createFromParcel(data);
 
-                    Uri out = insert(callingPkg, url, values);
+                    Uri out = insert(callingPkg, featureId, url, values);
                     reply.writeNoException();
                     Uri.writeToParcel(reply, out);
                     return true;
@@ -161,10 +164,11 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
 
-                    int count = bulkInsert(callingPkg, url, values);
+                    int count = bulkInsert(callingPkg, featureId, url, values);
                     reply.writeNoException();
                     reply.writeInt(count);
                     return true;
@@ -174,6 +178,7 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     String authority = data.readString();
                     final int numOperations = data.readInt();
                     final ArrayList<ContentProviderOperation> operations =
@@ -181,8 +186,8 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                     for (int i = 0; i < numOperations; i++) {
                         operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
                     }
-                    final ContentProviderResult[] results = applyBatch(callingPkg, authority,
-                            operations);
+                    final ContentProviderResult[] results = applyBatch(callingPkg, featureId,
+                            authority, operations);
                     reply.writeNoException();
                     reply.writeTypedArray(results, 0);
                     return true;
@@ -192,11 +197,12 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String selection = data.readString();
                     String[] selectionArgs = data.readStringArray();
 
-                    int count = delete(callingPkg, url, selection, selectionArgs);
+                    int count = delete(callingPkg, featureId, url, selection, selectionArgs);
 
                     reply.writeNoException();
                     reply.writeInt(count);
@@ -207,12 +213,14 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     ContentValues values = ContentValues.CREATOR.createFromParcel(data);
                     String selection = data.readString();
                     String[] selectionArgs = data.readStringArray();
 
-                    int count = update(callingPkg, url, values, selection, selectionArgs);
+                    int count = update(callingPkg, featureId, url, values, selection,
+                            selectionArgs);
 
                     reply.writeNoException();
                     reply.writeInt(count);
@@ -223,6 +231,7 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mode = data.readString();
                     ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
@@ -230,7 +239,7 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                     IBinder callerToken = data.readStrongBinder();
 
                     ParcelFileDescriptor fd;
-                    fd = openFile(callingPkg, url, mode, signal, callerToken);
+                    fd = openFile(callingPkg, featureId, url, mode, signal, callerToken);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -246,13 +255,14 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mode = data.readString();
                     ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
                             data.readStrongBinder());
 
                     AssetFileDescriptor fd;
-                    fd = openAssetFile(callingPkg, url, mode, signal);
+                    fd = openAssetFile(callingPkg, featureId, url, mode, signal);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -269,12 +279,14 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                     data.enforceInterface(IContentProvider.descriptor);
 
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     String authority = data.readString();
                     String method = data.readString();
                     String stringArg = data.readString();
                     Bundle args = data.readBundle();
 
-                    Bundle responseBundle = call(callingPkg, authority, method, stringArg, args);
+                    Bundle responseBundle = call(callingPkg, featureId, authority, method,
+                            stringArg, args);
 
                     reply.writeNoException();
                     reply.writeBundle(responseBundle);
@@ -297,6 +309,7 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mimeType = data.readString();
                     Bundle opts = data.readBundle();
@@ -304,7 +317,7 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                             data.readStrongBinder());
 
                     AssetFileDescriptor fd;
-                    fd = openTypedAssetFile(callingPkg, url, mimeType, opts, signal);
+                    fd = openTypedAssetFile(callingPkg, featureId, url, mimeType, opts, signal);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -330,9 +343,10 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
 
-                    Uri out = canonicalize(callingPkg, url);
+                    Uri out = canonicalize(callingPkg, featureId, url);
                     reply.writeNoException();
                     Uri.writeToParcel(reply, out);
                     return true;
@@ -342,9 +356,10 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
 
-                    Uri out = uncanonicalize(callingPkg, url);
+                    Uri out = uncanonicalize(callingPkg, featureId, url);
                     reply.writeNoException();
                     Uri.writeToParcel(reply, out);
                     return true;
@@ -353,12 +368,13 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 case REFRESH_TRANSACTION: {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     Bundle args = data.readBundle();
                     ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
                             data.readStrongBinder());
 
-                    boolean out = refresh(callingPkg, url, args, signal);
+                    boolean out = refresh(callingPkg, featureId, url, args, signal);
                     reply.writeNoException();
                     reply.writeInt(out ? 0 : -1);
                     return true;
@@ -367,11 +383,12 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
                 case CHECK_URI_PERMISSION_TRANSACTION: {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri uri = Uri.CREATOR.createFromParcel(data);
                     int uid = data.readInt();
                     int modeFlags = data.readInt();
 
-                    int out = checkUriPermission(callingPkg, uri, uid, modeFlags);
+                    int out = checkUriPermission(callingPkg, featureId, uri, uid, modeFlags);
                     reply.writeNoException();
                     reply.writeInt(out);
                     return true;
@@ -407,8 +424,9 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public Cursor query(String callingPkg, Uri url, @Nullable String[] projection,
-            @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
+    public Cursor query(String callingPkg, @Nullable String featureId, Uri url,
+            @Nullable String[] projection, @Nullable Bundle queryArgs,
+            @Nullable ICancellationSignal cancellationSignal)
             throws RemoteException {
         BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
         Parcel data = Parcel.obtain();
@@ -417,6 +435,7 @@ final class ContentProviderProxy implements IContentProvider
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             int length = 0;
             if (projection != null) {
@@ -478,7 +497,8 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public Uri insert(String callingPkg, Uri url, ContentValues values) throws RemoteException
+    public Uri insert(String callingPkg, @Nullable String featureId, Uri url,
+            ContentValues values) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -486,6 +506,7 @@ final class ContentProviderProxy implements IContentProvider
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             values.writeToParcel(data, 0);
 
@@ -501,13 +522,15 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public int bulkInsert(String callingPkg, Uri url, ContentValues[] values) throws RemoteException {
+    public int bulkInsert(String callingPkg, @Nullable String featureId, Uri url,
+            ContentValues[] values) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeTypedArray(values, 0);
 
@@ -523,14 +546,15 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public ContentProviderResult[] applyBatch(String callingPkg, String authority,
-            ArrayList<ContentProviderOperation> operations)
-                    throws RemoteException, OperationApplicationException {
+    public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String featureId,
+            String authority, ArrayList<ContentProviderOperation> operations)
+            throws RemoteException, OperationApplicationException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
             data.writeString(callingPkg);
+            data.writeString(featureId);
             data.writeString(authority);
             data.writeInt(operations.size());
             for (ContentProviderOperation operation : operations) {
@@ -549,14 +573,15 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
-            throws RemoteException {
+    public int delete(String callingPkg, @Nullable String featureId, Uri url, String selection,
+            String[] selectionArgs) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeString(selection);
             data.writeStringArray(selectionArgs);
@@ -573,14 +598,15 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public int update(String callingPkg, Uri url, ContentValues values, String selection,
-            String[] selectionArgs) throws RemoteException {
+    public int update(String callingPkg, @Nullable String featureId, Uri url,
+            ContentValues values, String selection, String[] selectionArgs) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             values.writeToParcel(data, 0);
             data.writeString(selection);
@@ -598,8 +624,8 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public ParcelFileDescriptor openFile(
-            String callingPkg, Uri url, String mode, ICancellationSignal signal, IBinder token)
+    public ParcelFileDescriptor openFile(String callingPkg, @Nullable String featureId, Uri url,
+            String mode, ICancellationSignal signal, IBinder token)
             throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -607,6 +633,7 @@ final class ContentProviderProxy implements IContentProvider
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeString(mode);
             data.writeStrongBinder(signal != null ? signal.asBinder() : null);
@@ -626,8 +653,8 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public AssetFileDescriptor openAssetFile(
-            String callingPkg, Uri url, String mode, ICancellationSignal signal)
+    public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String featureId,
+            Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -635,6 +662,7 @@ final class ContentProviderProxy implements IContentProvider
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeString(mode);
             data.writeStrongBinder(signal != null ? signal.asBinder() : null);
@@ -653,14 +681,15 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public Bundle call(String callingPkg, String authority, String method, String request,
-            Bundle args) throws RemoteException {
+    public Bundle call(String callingPkg, @Nullable String featureId, String authority,
+            String method, String request, Bundle args) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             data.writeString(authority);
             data.writeString(method);
             data.writeString(request);
@@ -700,14 +729,16 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
-            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
+    public AssetFileDescriptor openTypedAssetFile(String callingPkg, @Nullable String featureId,
+            Uri url, String mimeType, Bundle opts, ICancellationSignal signal)
+            throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeString(mimeType);
             data.writeBundle(opts);
@@ -747,14 +778,15 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public Uri canonicalize(String callingPkg, Uri url) throws RemoteException
-    {
+    public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri url)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
 
             mRemote.transact(IContentProvider.CANONICALIZE_TRANSACTION, data, reply, 0);
@@ -769,13 +801,15 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public Uri uncanonicalize(String callingPkg, Uri url) throws RemoteException {
+    public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri url)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
 
             mRemote.transact(IContentProvider.UNCANONICALIZE_TRANSACTION, data, reply, 0);
@@ -790,14 +824,15 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public boolean refresh(String callingPkg, Uri url, Bundle args, ICancellationSignal signal)
-            throws RemoteException {
+    public boolean refresh(String callingPkg, @Nullable String featureId, Uri url, Bundle args,
+            ICancellationSignal signal) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeBundle(args);
             data.writeStrongBinder(signal != null ? signal.asBinder() : null);
@@ -814,14 +849,15 @@ final class ContentProviderProxy implements IContentProvider
     }
 
     @Override
-    public int checkUriPermission(String callingPkg, Uri url, int uid, int modeFlags)
-            throws RemoteException {
+    public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri url, int uid,
+            int modeFlags) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeInt(uid);
             data.writeInt(modeFlags);
index 7f9ea76..1031fe2 100644 (file)
@@ -649,6 +649,7 @@ public abstract class ContentResolver implements ContentInterface {
     public ContentResolver(@Nullable Context context, @Nullable ContentInterface wrapped) {
         mContext = context != null ? context : ActivityThread.currentApplication();
         mPackageName = mContext.getOpPackageName();
+        mFeatureId = mContext.getFeatureId();
         mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
         mWrapped = wrapped;
     }
@@ -968,7 +969,7 @@ public abstract class ContentResolver implements ContentInterface {
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
             try {
-                qCursor = unstableProvider.query(mPackageName, uri, projection,
+                qCursor = unstableProvider.query(mPackageName, mFeatureId, uri, projection,
                         queryArgs, remoteCancellationSignal);
             } catch (DeadObjectException e) {
                 // The remote process has died...  but we only hold an unstable
@@ -979,8 +980,8 @@ public abstract class ContentResolver implements ContentInterface {
                 if (stableProvider == null) {
                     return null;
                 }
-                qCursor = stableProvider.query(
-                        mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
+                qCursor = stableProvider.query(mPackageName, mFeatureId, uri, projection,
+                        queryArgs, remoteCancellationSignal);
             }
             if (qCursor == null) {
                 return null;
@@ -1070,7 +1071,7 @@ public abstract class ContentResolver implements ContentInterface {
         }
 
         try {
-            return provider.canonicalize(mPackageName, url);
+            return provider.canonicalize(mPackageName, mFeatureId, url);
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
@@ -1114,7 +1115,7 @@ public abstract class ContentResolver implements ContentInterface {
         }
 
         try {
-            return provider.uncanonicalize(mPackageName, url);
+            return provider.uncanonicalize(mPackageName, mFeatureId, url);
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
@@ -1163,7 +1164,8 @@ public abstract class ContentResolver implements ContentInterface {
                 remoteCancellationSignal = provider.createCancellationSignal();
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
-            return provider.refresh(mPackageName, url, args, remoteCancellationSignal);
+            return provider.refresh(mPackageName, mFeatureId, url, args,
+                    remoteCancellationSignal);
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
@@ -1564,7 +1566,7 @@ public abstract class ContentResolver implements ContentInterface {
 
                     try {
                         fd = unstableProvider.openAssetFile(
-                                mPackageName, uri, mode, remoteCancellationSignal);
+                                mPackageName, mFeatureId, uri, mode, remoteCancellationSignal);
                         if (fd == null) {
                             // The provider will be released by the finally{} clause
                             return null;
@@ -1579,7 +1581,7 @@ public abstract class ContentResolver implements ContentInterface {
                             throw new FileNotFoundException("No content provider: " + uri);
                         }
                         fd = stableProvider.openAssetFile(
-                                mPackageName, uri, mode, remoteCancellationSignal);
+                                mPackageName, mFeatureId, uri, mode, remoteCancellationSignal);
                         if (fd == null) {
                             // The provider will be released by the finally{} clause
                             return null;
@@ -1730,7 +1732,7 @@ public abstract class ContentResolver implements ContentInterface {
 
             try {
                 fd = unstableProvider.openTypedAssetFile(
-                        mPackageName, uri, mimeType, opts, remoteCancellationSignal);
+                        mPackageName, mFeatureId, uri, mimeType, opts, remoteCancellationSignal);
                 if (fd == null) {
                     // The provider will be released by the finally{} clause
                     return null;
@@ -1745,7 +1747,7 @@ public abstract class ContentResolver implements ContentInterface {
                     throw new FileNotFoundException("No content provider: " + uri);
                 }
                 fd = stableProvider.openTypedAssetFile(
-                        mPackageName, uri, mimeType, opts, remoteCancellationSignal);
+                        mPackageName, mFeatureId, uri, mimeType, opts, remoteCancellationSignal);
                 if (fd == null) {
                     // The provider will be released by the finally{} clause
                     return null;
@@ -1870,7 +1872,7 @@ public abstract class ContentResolver implements ContentInterface {
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            Uri createdRow = provider.insert(mPackageName, url, values);
+            Uri createdRow = provider.insert(mPackageName, mFeatureId, url, values);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
             return createdRow;
@@ -1951,7 +1953,7 @@ public abstract class ContentResolver implements ContentInterface {
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            int rowsCreated = provider.bulkInsert(mPackageName, url, values);
+            int rowsCreated = provider.bulkInsert(mPackageName, mFeatureId, url, values);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
             return rowsCreated;
@@ -1991,7 +1993,8 @@ public abstract class ContentResolver implements ContentInterface {
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
+            int rowsDeleted = provider.delete(mPackageName, mFeatureId, url, where,
+                    selectionArgs);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
             return rowsDeleted;
@@ -2035,7 +2038,8 @@ public abstract class ContentResolver implements ContentInterface {
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs);
+            int rowsUpdated = provider.update(mPackageName, mFeatureId, uri, values, where,
+                    selectionArgs);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
             return rowsUpdated;
@@ -2084,7 +2088,8 @@ public abstract class ContentResolver implements ContentInterface {
             throw new IllegalArgumentException("Unknown authority " + authority);
         }
         try {
-            final Bundle res = provider.call(mPackageName, authority, method, arg, extras);
+            final Bundle res = provider.call(mPackageName, mFeatureId, authority, method, arg,
+                    extras);
             Bundle.setDefusable(res, true);
             return res;
         } catch (RemoteException e) {
@@ -3436,6 +3441,11 @@ public abstract class ContentResolver implements ContentInterface {
         return mPackageName;
     }
 
+    /** @hide */
+    public @Nullable String getFeatureId() {
+        return mFeatureId;
+    }
+
     @UnsupportedAppUsage
     private static volatile IContentService sContentService;
     @UnsupportedAppUsage
@@ -3443,6 +3453,7 @@ public abstract class ContentResolver implements ContentInterface {
 
     @UnsupportedAppUsage
     final String mPackageName;
+    final @Nullable String mFeatureId;
     final int mTargetSdkVersion;
     final ContentInterface mWrapped;
 
index fade0ab..d2c97c4 100644 (file)
@@ -16,7 +16,6 @@
 
 package android.content;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.AssetFileDescriptor;
@@ -38,66 +37,96 @@ import java.util.ArrayList;
  * @hide
  */
 public interface IContentProvider extends IInterface {
-    public Cursor query(String callingPkg, Uri url, @Nullable String[] projection,
+    public Cursor query(String callingPkg, @Nullable String featureId, Uri url,
+            @Nullable String[] projection,
             @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
             throws RemoteException;
     public String getType(Uri url) throws RemoteException;
-    @UnsupportedAppUsage
-    public Uri insert(String callingPkg, Uri url, ContentValues initialValues)
-            throws RemoteException;
-    @UnsupportedAppUsage
-    public int bulkInsert(String callingPkg, Uri url, ContentValues[] initialValues)
-            throws RemoteException;
-    @UnsupportedAppUsage
-    public int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+            + "ContentProviderClient#insert(android.net.Uri, android.content.ContentValues)} "
+            + "instead")
+    public default Uri insert(String callingPkg, Uri url, ContentValues initialValues)
+            throws RemoteException {
+        return insert(callingPkg, null, url, initialValues);
+    }
+    public Uri insert(String callingPkg, String featureId, Uri url, ContentValues initialValues)
             throws RemoteException;
-    @UnsupportedAppUsage
-    public int update(String callingPkg, Uri url, ContentValues values, String selection,
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+            + "ContentProviderClient#bulkInsert(android.net.Uri, android.content.ContentValues[])"
+            + "} instead")
+    public default int bulkInsert(String callingPkg, Uri url, ContentValues[] initialValues)
+            throws RemoteException {
+        return bulkInsert(callingPkg, null, url, initialValues);
+    }
+    public int bulkInsert(String callingPkg, String featureId, Uri url,
+            ContentValues[] initialValues) throws RemoteException;
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+            + "ContentProviderClient#delete(android.net.Uri, java.lang.String, java.lang"
+            + ".String[])} instead")
+    public default int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
+            throws RemoteException {
+        return delete(callingPkg, null, url, selection, selectionArgs);
+    }
+    public int delete(String callingPkg, String featureId, Uri url, String selection,
             String[] selectionArgs) throws RemoteException;
-    public ParcelFileDescriptor openFile(
-            String callingPkg, Uri url, String mode, ICancellationSignal signal,
-            IBinder callerToken)
-            throws RemoteException, FileNotFoundException;
-    public AssetFileDescriptor openAssetFile(
-            String callingPkg, Uri url, String mode, ICancellationSignal signal)
-            throws RemoteException, FileNotFoundException;
-
     @Deprecated
-    public default ContentProviderResult[] applyBatch(String callingPkg,
-            ArrayList<ContentProviderOperation> operations)
-                    throws RemoteException, OperationApplicationException {
-        return applyBatch(callingPkg, "unknown", operations);
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+            + "ContentProviderClient#update(android.net.Uri, android.content.ContentValues, java"
+            + ".lang.String, java.lang.String[])} instead")
+    public default int update(String callingPkg, Uri url, ContentValues values, String selection,
+            String[] selectionArgs) throws RemoteException {
+        return update(callingPkg, null, url, values, selection, selectionArgs);
     }
+    public int update(String callingPkg, String featureId, Uri url, ContentValues values,
+            String selection, String[] selectionArgs) throws RemoteException;
+
+    public ParcelFileDescriptor openFile(String callingPkg, @Nullable String featureId, Uri url,
+            String mode, ICancellationSignal signal, IBinder callerToken)
+            throws RemoteException, FileNotFoundException;
 
-    public ContentProviderResult[] applyBatch(String callingPkg, String authority,
-            ArrayList<ContentProviderOperation> operations)
+    public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String featureId,
+            Uri url, String mode, ICancellationSignal signal)
+            throws RemoteException, FileNotFoundException;
+
+    public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String featureId,
+            String authority, ArrayList<ContentProviderOperation> operations)
             throws RemoteException, OperationApplicationException;
 
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+            + "ContentProviderClient#call(java.lang.String, java.lang.String, android.os.Bundle)} "
+            + "instead")
     public default Bundle call(String callingPkg, String method,
             @Nullable String arg, @Nullable Bundle extras) throws RemoteException {
-        return call(callingPkg, "unknown", method, arg, extras);
+        return call(callingPkg, null, "unknown", method, arg, extras);
     }
 
-    public Bundle call(String callingPkg, String authority, String method,
-            @Nullable String arg, @Nullable Bundle extras) throws RemoteException;
+    public Bundle call(String callingPkg, @Nullable String featureId, String authority,
+            String method, @Nullable String arg, @Nullable Bundle extras) throws RemoteException;
 
-    public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags)
-            throws RemoteException;
+    public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri, int uid,
+            int modeFlags) throws RemoteException;
 
     public ICancellationSignal createCancellationSignal() throws RemoteException;
 
-    public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException;
-    public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException;
+    public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+            throws RemoteException;
+
+    public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+            throws RemoteException;
 
-    public boolean refresh(String callingPkg, Uri url, @Nullable Bundle args,
-            ICancellationSignal cancellationSignal) throws RemoteException;
+    public boolean refresh(String callingPkg, @Nullable String featureId, Uri url,
+            @Nullable Bundle args, ICancellationSignal cancellationSignal) throws RemoteException;
 
     // Data interchange.
     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
-    public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
-            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException;
+
+    public AssetFileDescriptor openTypedAssetFile(String callingPkg, @Nullable String featureId,
+            Uri url, String mimeType, Bundle opts, ICancellationSignal signal)
+            throws RemoteException, FileNotFoundException;
 
     /* IPC constants */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
index 2143a0d..a80153d 100644 (file)
@@ -1081,7 +1081,8 @@ public abstract class DocumentsProvider extends ContentProvider {
             // signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for
             // MANAGE_DOCUMENTS or associated URI permission here instead
             final Uri rootUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
-            enforceWritePermissionInner(rootUri, getCallingPackage(), null);
+            enforceWritePermissionInner(rootUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final String rootId = DocumentsContract.getRootId(rootUri);
             ejectRoot(rootId);
@@ -1102,7 +1103,8 @@ public abstract class DocumentsProvider extends ContentProvider {
         enforceTree(documentUri);
 
         if (METHOD_IS_CHILD_DOCUMENT.equals(method)) {
-            enforceReadPermissionInner(documentUri, getCallingPackage(), null);
+            enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final Uri childUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
             final String childAuthority = childUri.getAuthority();
@@ -1114,7 +1116,8 @@ public abstract class DocumentsProvider extends ContentProvider {
                             && isChildDocument(documentId, childId));
 
         } else if (METHOD_CREATE_DOCUMENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
             final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
@@ -1128,7 +1131,8 @@ public abstract class DocumentsProvider extends ContentProvider {
             out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
 
         } else if (METHOD_CREATE_WEB_LINK_INTENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final Bundle options = extras.getBundle(DocumentsContract.EXTRA_OPTIONS);
             final IntentSender intentSender = createWebLinkIntent(documentId, options);
@@ -1136,7 +1140,8 @@ public abstract class DocumentsProvider extends ContentProvider {
             out.putParcelable(DocumentsContract.EXTRA_RESULT, intentSender);
 
         } else if (METHOD_RENAME_DOCUMENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
             final String newDocumentId = renameDocument(documentId, displayName);
@@ -1160,7 +1165,8 @@ public abstract class DocumentsProvider extends ContentProvider {
             }
 
         } else if (METHOD_DELETE_DOCUMENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
             deleteDocument(documentId);
 
             // Document no longer exists, clean up any grants.
@@ -1170,8 +1176,10 @@ public abstract class DocumentsProvider extends ContentProvider {
             final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
             final String targetId = DocumentsContract.getDocumentId(targetUri);
 
-            enforceReadPermissionInner(documentUri, getCallingPackage(), null);
-            enforceWritePermissionInner(targetUri, getCallingPackage(), null);
+            enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
+            enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final String newDocumentId = copyDocument(documentId, targetId);
 
@@ -1194,9 +1202,12 @@ public abstract class DocumentsProvider extends ContentProvider {
             final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
             final String targetId = DocumentsContract.getDocumentId(targetUri);
 
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
-            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), null);
-            enforceWritePermissionInner(targetUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
+            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
+            enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final String newDocumentId = moveDocument(documentId, parentSourceId, targetId);
 
@@ -1217,8 +1228,10 @@ public abstract class DocumentsProvider extends ContentProvider {
             final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI);
             final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri);
 
-            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), null);
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
             removeDocument(documentId, parentSourceId);
 
             // It's responsibility of the provider to revoke any grants, as the document may be
@@ -1227,7 +1240,8 @@ public abstract class DocumentsProvider extends ContentProvider {
             final boolean isTreeUri = isTreeUri(documentUri);
 
             if (isTreeUri) {
-                enforceReadPermissionInner(documentUri, getCallingPackage(), null);
+                enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                        null);
             } else {
                 getContext().enforceCallingPermission(Manifest.permission.MANAGE_DOCUMENTS, null);
             }
index b5580d4..cce7c42 100644 (file)
@@ -2306,8 +2306,8 @@ public final class Settings {
                     arg.putBoolean(CALL_METHOD_MAKE_DEFAULT_KEY, true);
                 }
                 IContentProvider cp = mProviderHolder.getProvider(cr);
-                cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
-                        mCallSetCommand, name, arg);
+                cp.call(cr.getPackageName(), cr.getFeatureId(),
+                        mProviderHolder.mUri.getAuthority(), mCallSetCommand, name, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
                 return false;
@@ -2380,14 +2380,15 @@ public final class Settings {
                     if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
                         final long token = Binder.clearCallingIdentity();
                         try {
-                            b = cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
-                                    mCallGetCommand, name, args);
+                            b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+                                    mProviderHolder.mUri.getAuthority(), mCallGetCommand, name,
+                                    args);
                         } finally {
                             Binder.restoreCallingIdentity(token);
                         }
                     } else {
-                        b = cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
-                                mCallGetCommand, name, args);
+                        b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+                                mProviderHolder.mUri.getAuthority(), mCallGetCommand, name, args);
                     }
                     if (b != null) {
                         String value = b.getString(Settings.NameValueTable.VALUE);
@@ -2455,14 +2456,14 @@ public final class Settings {
                 if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
                     final long token = Binder.clearCallingIdentity();
                     try {
-                        c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs,
-                                null);
+                        c = cp.query(cr.getPackageName(), cr.getFeatureId(), mUri,
+                                SELECT_VALUE_PROJECTION, queryArgs, null);
                     } finally {
                         Binder.restoreCallingIdentity(token);
                     }
                 } else {
-                    c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs,
-                            null);
+                    c = cp.query(cr.getPackageName(), cr.getFeatureId(), mUri,
+                            SELECT_VALUE_PROJECTION, queryArgs, null);
                 }
                 if (c == null) {
                     Log.w(TAG, "Can't get key " + name + " from " + mUri);
@@ -2557,8 +2558,8 @@ public final class Settings {
                 }
 
                 // Fetch all flags for the namespace at once for caching purposes
-                Bundle b = cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
-                        mCallListCommand, null, args);
+                Bundle b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+                        mProviderHolder.mUri.getAuthority(), mCallListCommand, null, args);
                 if (b == null) {
                     // Invalid response, return an empty map
                     return keyValues;
@@ -5132,8 +5133,8 @@ public final class Settings {
                 }
                 arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
-                        CALL_METHOD_RESET_SECURE, null, arg);
+                cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+                        sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_SECURE, null, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
             }
@@ -12821,8 +12822,8 @@ public final class Settings {
                 }
                 arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
-                        CALL_METHOD_RESET_GLOBAL, null, arg);
+                cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+                        sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_GLOBAL, null, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
             }
@@ -13758,8 +13759,8 @@ public final class Settings {
                     arg.putString(Settings.CALL_METHOD_PREFIX_KEY, prefix);
                 }
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
-                        CALL_METHOD_RESET_CONFIG, null, arg);
+                cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+                        sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_CONFIG, null, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't reset to defaults for " + DeviceConfig.CONTENT_URI, e);
             }
index f14f289..88967b5 100644 (file)
@@ -82,7 +82,8 @@ public class ContentResolverTest {
 
         final AssetFileDescriptor afd = new AssetFileDescriptor(
                 new ParcelFileDescriptor(mImage.getFileDescriptor()), 0, mSize, null);
-        when(mProvider.openTypedAssetFile(any(), any(), any(), any(), any())).thenReturn(afd);
+        when(mProvider.openTypedAssetFile(any(), any(), any(), any(), any(), any())).thenReturn(
+                afd);
     }
 
     private static void assertImageAspectAndContents(Bitmap bitmap) {
index 1bd8ff6..5f640be 100644 (file)
@@ -93,12 +93,14 @@ public class TestDocumentsProvider extends DocumentsProvider {
     }
 
     @Override
-    protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken) {
+    protected int enforceReadPermissionInner(Uri uri, String callingPkg,
+            @Nullable String callingFeatureId, IBinder callerToken) {
         return AppOpsManager.MODE_ALLOWED;
     }
 
     @Override
-    protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken) {
+    protected int enforceWritePermissionInner(Uri uri, String callingPkg,
+            @Nullable String callingFeatureId, IBinder callerToken) {
         return AppOpsManager.MODE_ALLOWED;
     }
 
index 74bf1a2..de353bf 100644 (file)
@@ -42,6 +42,7 @@ import org.mockito.MockitoAnnotations;
 
 public class MediaInserterTest extends InstrumentationTestCase {
 
+    private static final String TEST_FEATURE_ID = "testFeature";
     private MediaInserter mMediaInserter;
     private static final int TEST_BUFFER_SIZE = 10;
     private @Mock IContentProvider mMockProvider;
@@ -86,7 +87,8 @@ public class MediaInserterTest extends InstrumentationTestCase {
         MockitoAnnotations.initMocks(this);
 
         final ContentProviderClient client = new ContentProviderClient(
-                getInstrumentation().getContext().getContentResolver(), mMockProvider, true);
+                getInstrumentation().getContext().createFeatureContext(TEST_FEATURE_ID)
+                        .getContentResolver(), mMockProvider, true);
         mMediaInserter = new MediaInserter(client, TEST_BUFFER_SIZE);
         mPackageName = getInstrumentation().getContext().getPackageName();
         mFilesCounter = 0;
@@ -142,31 +144,36 @@ public class MediaInserterTest extends InstrumentationTestCase {
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE - 2);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE - 1);
 
-        verify(mMockProvider, never()).bulkInsert(eq(mPackageName), any(), any());
+        verify(mMockProvider, never()).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any());
     }
 
     @SmallTest
     public void testInsertContentsEqualToBufferSize() throws Exception {
-        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE);
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE);
 
-        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), any(), any());
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any());
     }
 
     @SmallTest
     public void testInsertContentsMoreThanBufferSize() throws Exception {
-        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE + 1);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE + 2);
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE + 3);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE + 4);
 
-        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), any(), any());
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any());
     }
 
     @SmallTest
@@ -176,7 +183,8 @@ public class MediaInserterTest extends InstrumentationTestCase {
 
     @SmallTest
     public void testFlushAllWithSomeContents() throws Exception {
-        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE - 4);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE - 3);
@@ -184,12 +192,14 @@ public class MediaInserterTest extends InstrumentationTestCase {
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE - 1);
         mMediaInserter.flushAll();
 
-        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), any(), any());
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any());
     }
 
     @SmallTest
     public void testInsertContentsAfterFlushAll() throws Exception {
-        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE - 4);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE - 3);
@@ -202,15 +212,20 @@ public class MediaInserterTest extends InstrumentationTestCase {
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE + 3);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE + 4);
 
-        verify(mMockProvider, times(8)).bulkInsert(eq(mPackageName), any(), any());
+        verify(mMockProvider, times(8)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any());
     }
 
     @SmallTest
     public void testInsertContentsWithDifferentSizePerContentType() throws Exception {
-        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sFilesUri), any())).thenReturn(1);
-        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sAudioUri), any())).thenReturn(1);
-        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sVideoUri), any())).thenReturn(1);
-        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sImagesUri), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), eqUri(sFilesUri),
+                any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), eqUri(sAudioUri),
+                any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), eqUri(sVideoUri),
+                any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), eqUri(sImagesUri),
+                any())).thenReturn(1);
 
         for (int i = 0; i < TEST_BUFFER_SIZE; ++i) {
             fillBuffer(sFilesUri, 1);
@@ -219,9 +234,13 @@ public class MediaInserterTest extends InstrumentationTestCase {
             fillBuffer(sImagesUri, 4);
         }
 
-        verify(mMockProvider, times(1)).bulkInsert(eq(mPackageName), eqUri(sFilesUri), any());
-        verify(mMockProvider, times(2)).bulkInsert(eq(mPackageName), eqUri(sAudioUri), any());
-        verify(mMockProvider, times(3)).bulkInsert(eq(mPackageName), eqUri(sVideoUri), any());
-        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eqUri(sImagesUri), any());
+        verify(mMockProvider, times(1)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID),
+                eqUri(sFilesUri), any());
+        verify(mMockProvider, times(2)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID),
+                eqUri(sAudioUri), any());
+        verify(mMockProvider, times(3)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID),
+                eqUri(sVideoUri), any());
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID),
+                eqUri(sImagesUri), any());
     }
 }
index 48d34ae..af96982 100644 (file)
@@ -129,17 +129,17 @@ public class ExternalStorageProvider extends FileSystemProvider {
     }
 
     @Override
-    protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken)
-            throws SecurityException {
+    protected int enforceReadPermissionInner(Uri uri, String callingPkg,
+            @Nullable String featureId, IBinder callerToken) throws SecurityException {
         enforceShellRestrictions();
-        return super.enforceReadPermissionInner(uri, callingPkg, callerToken);
+        return super.enforceReadPermissionInner(uri, callingPkg, featureId, callerToken);
     }
 
     @Override
-    protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken)
-            throws SecurityException {
+    protected int enforceWritePermissionInner(Uri uri, String callingPkg,
+            @Nullable String featureId, IBinder callerToken) throws SecurityException {
         enforceShellRestrictions();
-        return super.enforceWritePermissionInner(uri, callingPkg, callerToken);
+        return super.enforceWritePermissionInner(uri, callingPkg, featureId, callerToken);
     }
 
     public void updateVolumes() {
index c4df2e8..b9daf7f 100644 (file)
@@ -406,8 +406,8 @@ public class TileUtils {
             return null;
         }
         try {
-            return provider.call(context.getPackageName(), uri.getAuthority(),
-                    method, uri.toString(), bundle);
+            return provider.call(context.getPackageName(), context.getFeatureId(),
+                    uri.getAuthority(), method, uri.toString(), bundle);
         } catch (RemoteException e) {
             return null;
         }
index 8fb879d..1e75fe7 100644 (file)
@@ -248,7 +248,7 @@ public final class DeviceConfigService extends Binder {
                 Bundle args = new Bundle();
                 args.putInt(Settings.CALL_METHOD_USER_KEY,
                         ActivityManager.getService().getCurrentUser().id);
-                Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                Bundle b = provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         Settings.CALL_METHOD_DELETE_CONFIG, compositeKey, args);
                 success = (b != null && b.getInt(SettingsProvider.RESULT_ROWS_DELETED) == 1);
             } catch (RemoteException e) {
@@ -264,7 +264,7 @@ public final class DeviceConfigService extends Binder {
                 Bundle args = new Bundle();
                 args.putInt(Settings.CALL_METHOD_USER_KEY,
                         ActivityManager.getService().getCurrentUser().id);
-                Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                Bundle b = provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         Settings.CALL_METHOD_LIST_CONFIG, null, args);
                 if (b != null) {
                     Map<String, String> flagsToValues =
index 36360a3..3b3ca5b 100644 (file)
@@ -309,7 +309,7 @@ final public class SettingsService extends Binder {
             try {
                 Bundle arg = new Bundle();
                 arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-                Bundle result = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                Bundle result = provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         callListCommand, null, arg);
                 lines.addAll(result.getStringArrayList(SettingsProvider.RESULT_SETTINGS_LIST));
                 Collections.sort(lines);
@@ -334,7 +334,7 @@ final public class SettingsService extends Binder {
             try {
                 Bundle arg = new Bundle();
                 arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-                Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                Bundle b = provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         callGetCommand, key, arg);
                 if (b != null) {
                     result = b.getPairValue();
@@ -372,7 +372,7 @@ final public class SettingsService extends Binder {
                 if (makeDefault) {
                     arg.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
                 }
-                provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         callPutCommand, key, arg);
             } catch (RemoteException e) {
                 throw new RuntimeException("Failed in IPC", e);
@@ -396,7 +396,7 @@ final public class SettingsService extends Binder {
             try {
                 Bundle arg = new Bundle();
                 arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-                Bundle result = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                Bundle result = provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         callDeleteCommand, key, arg);
                 return result.getInt(SettingsProvider.RESULT_ROWS_DELETED);
             } catch (RemoteException e) {
@@ -423,7 +423,7 @@ final public class SettingsService extends Binder {
                 }
                 String packageName = mPackageName != null ? mPackageName : resolveCallingPackage();
                 arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-                provider.call(packageName, Settings.AUTHORITY, callResetCommand, null, arg);
+                provider.call(packageName, null, Settings.AUTHORITY, callResetCommand, null, arg);
             } catch (RemoteException e) {
                 throw new RuntimeException("Failed in IPC", e);
             }
index 11cfe12..5df4543 100644 (file)
@@ -7758,7 +7758,7 @@ public class ActivityManagerService extends IActivityManager.Stub
             holder = getContentProviderExternalUnchecked(name, null, callingUid,
                     "*checkContentProviderUriPermission*", userId);
             if (holder != null) {
-                return holder.provider.checkUriPermission(null, uri, callingUid, modeFlags);
+                return holder.provider.checkUriPermission(null, null, uri, callingUid, modeFlags);
             }
         } catch (RemoteException e) {
             Log.w(TAG, "Content provider dead retrieving " + uri, e);
@@ -7923,7 +7923,7 @@ public class ActivityManagerService extends IActivityManager.Stub
             sCallerIdentity.set(new Identity(
                     token, Binder.getCallingPid(), Binder.getCallingUid()));
             try {
-                pfd = cph.provider.openFile(null, uri, "r", null, token);
+                pfd = cph.provider.openFile(null, null, uri, "r", null, token);
             } catch (FileNotFoundException e) {
                 // do nothing; pfd will be returned null
             } finally {
index 1ad7b6e..79af34d 100644 (file)
@@ -191,7 +191,7 @@ public class NetworkScoreServiceTest {
     @After
     public void tearDown() throws Exception {
         mHandlerThread.quitSafely();
-        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.removeServiceForTest(PermissionManagerServiceInternal.class);
     }
 
     @Test
index 80439cf..a1322b9 100644 (file)
@@ -62,7 +62,6 @@ import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
-
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableContentResolver;
 import android.util.ArrayMap;
@@ -162,11 +161,11 @@ public class PreferencesHelperTest extends UiServiceTestCase {
         when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
         contentResolver.addProvider(TEST_AUTHORITY, testContentProvider);
 
-        when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI)))
                 .thenReturn(CANONICAL_SOUND_URI);
-        when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(CANONICAL_SOUND_URI);
-        when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(SOUND_URI);
 
         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
@@ -465,7 +464,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
 
         // Testing that in restore we are given the canonical version
         loadStreamXml(baos, true, UserHandle.USER_SYSTEM);
-        verify(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
+        verify(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
     }
 
     @Test
@@ -475,11 +474,11 @@ public class PreferencesHelperTest extends UiServiceTestCase {
                 .appendQueryParameter("title", "Test")
                 .appendQueryParameter("canonical", "1")
                 .build();
-        when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(canonicalBasedOnLocal);
-        when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(localUri);
-        when(mTestIContentProvider.uncanonicalize(any(), eq(canonicalBasedOnLocal)))
+        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(canonicalBasedOnLocal)))
                 .thenReturn(localUri);
 
         NotificationChannel channel =
@@ -499,9 +498,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
     @Test
     public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception {
         Thread.sleep(3000);
-        when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(null);
-        when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(null);
 
         NotificationChannel channel =
@@ -526,7 +525,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
     @Test
     public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception {
         // Not a local uncanonicalized uri, simulating that it fails to exist locally
-        when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI))).thenReturn(null);
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI))).thenReturn(null);
         String id = "id";
         String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
index 2abd340..8774b63 100644 (file)
@@ -132,11 +132,11 @@ public class RankingHelperTest extends UiServiceTestCase {
         when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
         contentResolver.addProvider(TEST_AUTHORITY, testContentProvider);
 
-        when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI)))
                 .thenReturn(CANONICAL_SOUND_URI);
-        when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(CANONICAL_SOUND_URI);
-        when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(SOUND_URI);
 
         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
index 3b336eb..aceed86 100644 (file)
@@ -12,6 +12,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -109,8 +110,8 @@ public class PinnedSliceStateTest extends UiServiceTestCase {
         mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
         TestableLooper.get(this).processAllMessages();
 
-        verify(mIContentProvider).call(anyString(), anyString(), eq(SliceProvider.METHOD_PIN),
-                eq(null), argThat(b -> {
+        verify(mIContentProvider).call(anyString(), nullable(String.class), anyString(),
+                eq(SliceProvider.METHOD_PIN), eq(null), argThat(b -> {
                     assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
                     return true;
                 }));
@@ -167,8 +168,8 @@ public class PinnedSliceStateTest extends UiServiceTestCase {
         // Throw exception when trying to pin
         doAnswer(invocation -> {
             throw new Exception("Pin failed");
-        }).when(mIContentProvider).call(
-                anyString(), anyString(), anyString(), eq(null), any());
+        }).when(mIContentProvider).call(anyString(), nullable(String.class), anyString(),
+                anyString(), eq(null), any());
 
         TestableLooper.get(this).processAllMessages();
 
@@ -176,8 +177,8 @@ public class PinnedSliceStateTest extends UiServiceTestCase {
         mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
         TestableLooper.get(this).processAllMessages();
 
-        verify(mIContentProvider).call(anyString(), anyString(), eq(SliceProvider.METHOD_PIN),
-                eq(null), argThat(b -> {
+        verify(mIContentProvider).call(anyString(), nullable(String.class), anyString(),
+                eq(SliceProvider.METHOD_PIN), eq(null), argThat(b -> {
                     assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
                     return true;
                 }));
index 4d8c7d9..9d3e120 100644 (file)
@@ -56,21 +56,22 @@ public class MockContentProvider extends ContentProvider {
      */
     private class InversionIContentProvider implements IContentProvider {
         @Override
-        public ContentProviderResult[] applyBatch(String callingPackage, String authority,
+        public ContentProviderResult[] applyBatch(String callingPackage,
+                @Nullable String featureId, String authority,
                 ArrayList<ContentProviderOperation> operations)
                 throws RemoteException, OperationApplicationException {
             return MockContentProvider.this.applyBatch(authority, operations);
         }
 
         @Override
-        public int bulkInsert(String callingPackage, Uri url, ContentValues[] initialValues)
-                throws RemoteException {
+        public int bulkInsert(String callingPackage, @Nullable String featureId, Uri url,
+                ContentValues[] initialValues) throws RemoteException {
             return MockContentProvider.this.bulkInsert(url, initialValues);
         }
 
         @Override
-        public int delete(String callingPackage, Uri url, String selection, String[] selectionArgs)
-                throws RemoteException {
+        public int delete(String callingPackage, @Nullable String featureId, Uri url,
+                String selection, String[] selectionArgs) throws RemoteException {
             return MockContentProvider.this.delete(url, selection, selectionArgs);
         }
 
@@ -80,42 +81,42 @@ public class MockContentProvider extends ContentProvider {
         }
 
         @Override
-        public Uri insert(String callingPackage, Uri url, ContentValues initialValues)
-                throws RemoteException {
+        public Uri insert(String callingPackage, @Nullable String featureId, Uri url,
+                ContentValues initialValues) throws RemoteException {
             return MockContentProvider.this.insert(url, initialValues);
         }
 
         @Override
-        public AssetFileDescriptor openAssetFile(
-                String callingPackage, Uri url, String mode, ICancellationSignal signal)
+        public AssetFileDescriptor openAssetFile(String callingPackage,
+                @Nullable String featureId, Uri url, String mode, ICancellationSignal signal)
                 throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openAssetFile(url, mode);
         }
 
         @Override
-        public ParcelFileDescriptor openFile(
-                String callingPackage, Uri url, String mode, ICancellationSignal signal,
-                IBinder callerToken) throws RemoteException, FileNotFoundException {
+        public ParcelFileDescriptor openFile(String callingPackage, @Nullable String featureId,
+                Uri url, String mode, ICancellationSignal signal, IBinder callerToken)
+                throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openFile(url, mode);
         }
 
         @Override
-        public Cursor query(String callingPackage, Uri url, @Nullable String[] projection,
-                @Nullable Bundle queryArgs,
-                @Nullable ICancellationSignal cancellationSignal)
-                throws RemoteException {
+        public Cursor query(String callingPackage, @Nullable String featureId, Uri url,
+                @Nullable String[] projection, @Nullable Bundle queryArgs,
+                @Nullable ICancellationSignal cancellationSignal) throws RemoteException {
             return MockContentProvider.this.query(url, projection, queryArgs, null);
         }
 
         @Override
-        public int update(String callingPackage, Uri url, ContentValues values, String selection,
-                String[] selectionArgs) throws RemoteException {
+        public int update(String callingPackage, @Nullable String featureId, Uri url,
+                ContentValues values, String selection, String[] selectionArgs)
+                throws RemoteException {
             return MockContentProvider.this.update(url, values, selection, selectionArgs);
         }
 
         @Override
-        public Bundle call(String callingPackage, String authority, String method, String request,
-                Bundle args) throws RemoteException {
+        public Bundle call(String callingPackage, @Nullable String featureId, String authority,
+                String method, String request, Bundle args) throws RemoteException {
             return MockContentProvider.this.call(authority, method, request, args);
         }
 
@@ -130,9 +131,9 @@ public class MockContentProvider extends ContentProvider {
         }
 
         @Override
-        public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri url,
-                String mimeType, Bundle opts, ICancellationSignal signal)
-                throws RemoteException, FileNotFoundException {
+        public AssetFileDescriptor openTypedAssetFile(String callingPackage,
+                @Nullable String featureId, Uri url, String mimeType, Bundle opts,
+                ICancellationSignal signal) throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openTypedAssetFile(url, mimeType, opts);
         }
 
@@ -142,23 +143,26 @@ public class MockContentProvider extends ContentProvider {
         }
 
         @Override
-        public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException {
+        public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+                throws RemoteException {
             return MockContentProvider.this.canonicalize(uri);
         }
 
         @Override
-        public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
+        public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+                throws RemoteException {
             return MockContentProvider.this.uncanonicalize(uri);
         }
 
         @Override
-        public boolean refresh(String callingPkg, Uri url, Bundle args,
-                ICancellationSignal cancellationSignal) throws RemoteException {
+        public boolean refresh(String callingPkg, @Nullable String featureId, Uri url,
+                Bundle args, ICancellationSignal cancellationSignal) throws RemoteException {
             return MockContentProvider.this.refresh(url, args);
         }
 
         @Override
-        public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags) {
+        public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri,
+                int uid, int modeFlags) {
             return MockContentProvider.this.checkUriPermission(uri, uid, modeFlags);
         }
     }
index b072d74..e512b52 100644 (file)
 
 package android.test.mock;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentProviderOperation;
 import android.content.ContentProviderResult;
 import android.content.ContentValues;
 import android.content.EntityIterator;
 import android.content.IContentProvider;
-import android.content.Intent;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
@@ -45,14 +43,15 @@ import java.util.ArrayList;
  */
 public class MockIContentProvider implements IContentProvider {
     @Override
-    public int bulkInsert(String callingPackage, Uri url, ContentValues[] initialValues) {
+    public int bulkInsert(String callingPackage, @Nullable String featureId, Uri url,
+            ContentValues[] initialValues) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
     @SuppressWarnings("unused")
-    public int delete(String callingPackage, Uri url, String selection, String[] selectionArgs)
-            throws RemoteException {
+    public int delete(String callingPackage, @Nullable String featureId, Uri url,
+            String selection, String[] selectionArgs) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -63,33 +62,33 @@ public class MockIContentProvider implements IContentProvider {
 
     @Override
     @SuppressWarnings("unused")
-    public Uri insert(String callingPackage, Uri url, ContentValues initialValues)
-            throws RemoteException {
+    public Uri insert(String callingPackage, @Nullable String featureId, Uri url,
+            ContentValues initialValues) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public ParcelFileDescriptor openFile(
-            String callingPackage, Uri url, String mode, ICancellationSignal signal,
-            IBinder callerToken) {
+    public ParcelFileDescriptor openFile(String callingPackage, @Nullable String featureId,
+            Uri url, String mode, ICancellationSignal signal, IBinder callerToken) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public AssetFileDescriptor openAssetFile(
-            String callingPackage, Uri uri, String mode, ICancellationSignal signal) {
+    public AssetFileDescriptor openAssetFile(String callingPackage, @Nullable String featureId,
+            Uri uri, String mode, ICancellationSignal signal) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public ContentProviderResult[] applyBatch(String callingPackage, String authority,
-            ArrayList<ContentProviderOperation> operations) {
+    public ContentProviderResult[] applyBatch(String callingPackage, @Nullable String featureId,
+            String authority, ArrayList<ContentProviderOperation> operations) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public Cursor query(String callingPackage, Uri url, @Nullable String[] projection,
-            @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
+    public Cursor query(String callingPackage, @Nullable String featureId, Uri url,
+            @Nullable String[] projection, @Nullable Bundle queryArgs,
+            @Nullable ICancellationSignal cancellationSignal) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -99,14 +98,14 @@ public class MockIContentProvider implements IContentProvider {
     }
 
     @Override
-    public int update(String callingPackage, Uri url, ContentValues values, String selection,
-            String[] selectionArgs) throws RemoteException {
+    public int update(String callingPackage, @Nullable String featureId, Uri url,
+            ContentValues values, String selection, String[] selectionArgs) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public Bundle call(String callingPackage, String authority, String method, String request,
-            Bundle args) throws RemoteException {
+    public Bundle call(String callingPackage, @Nullable String featureId, String authority,
+            String method, String request, Bundle args) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -121,8 +120,9 @@ public class MockIContentProvider implements IContentProvider {
     }
 
     @Override
-    public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri url, String mimeType,
-            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
+    public AssetFileDescriptor openTypedAssetFile(String callingPackage,
+            @Nullable String featureId, Uri url, String mimeType, Bundle opts,
+            ICancellationSignal signal) throws RemoteException, FileNotFoundException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -132,24 +132,27 @@ public class MockIContentProvider implements IContentProvider {
     }
 
     @Override
-    public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException {
+    public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+            throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
+    public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+            throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public boolean refresh(String callingPkg, Uri url, Bundle args,
+    public boolean refresh(String callingPkg, @Nullable String featureId, Uri url, Bundle args,
             ICancellationSignal cancellationSignal) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     /** {@hide} */
     @Override
-    public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags) {
+    public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri, int uid,
+            int modeFlags) {
         throw new UnsupportedOperationException("unimplemented mock method call");
     }
 }