diff options
6 files changed, 65 insertions, 7 deletions
diff --git a/api/current.txt b/api/current.txt index 0fcf929bc277..b3c4102a14f0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -7306,6 +7306,7 @@ package android.app.slice { } public abstract class SliceProvider extends android.content.ContentProvider { + ctor public SliceProvider(java.lang.String...); ctor public SliceProvider(); method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public final java.lang.String getType(android.net.Uri); diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl index 74e3c3ee4c81..a2aaf12432f8 100644 --- a/core/java/android/app/slice/ISliceManager.aidl +++ b/core/java/android/app/slice/ISliceManager.aidl @@ -25,7 +25,8 @@ interface ISliceManager { void unpinSlice(String pkg, in Uri uri, in IBinder token); boolean hasSliceAccess(String pkg); SliceSpec[] getPinnedSpecs(in Uri uri, String pkg); - int checkSlicePermission(in Uri uri, String pkg, int pid, int uid); + int checkSlicePermission(in Uri uri, String pkg, int pid, int uid, + in String[] autoGrantPermissions); void grantPermissionFromUser(in Uri uri, String pkg, String callingPkg, boolean allSlices); Uri[] getPinnedSlices(String pkg); diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java index 1afe53d8a7b5..d36dea8295f1 100644 --- a/core/java/android/app/slice/SliceManager.java +++ b/core/java/android/app/slice/SliceManager.java @@ -392,7 +392,8 @@ public class SliceManager { * Does the permission check to see if a caller has access to a specific slice. * @hide */ - public void enforceSlicePermission(Uri uri, String pkg, int pid, int uid) { + public void enforceSlicePermission(Uri uri, String pkg, int pid, int uid, + String[] autoGrantPermissions) { try { if (UserHandle.isSameApp(uid, Process.myUid())) { return; @@ -400,7 +401,7 @@ public class SliceManager { if (pkg == null) { throw new SecurityException("No pkg specified"); } - int result = mService.checkSlicePermission(uri, pkg, pid, uid); + int result = mService.checkSlicePermission(uri, pkg, pid, uid, autoGrantPermissions); if (result == PERMISSION_DENIED) { throw new SecurityException("User " + uid + " does not have slice permission for " + uri + "."); @@ -412,6 +413,8 @@ public class SliceManager { Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); + // Notify a change has happened because we just granted a permission. + mContext.getContentResolver().notifyChange(uri, null); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index bbeb3849be78..fe5742d6da38 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -149,10 +149,31 @@ public abstract class SliceProvider extends ContentProvider { private static final boolean DEBUG = false; private static final long SLICE_BIND_ANR = 2000; + private final String[] mAutoGrantPermissions; private String mCallback; private SliceManager mSliceManager; + /** + * A version of constructing a SliceProvider that allows autogranting slice permissions + * to apps that hold specific platform permissions. + * <p> + * When an app tries to bind a slice from this provider that it does not have access to, + * This provider will check if the caller holds permissions to any of the autoGrantPermissions + * specified, if they do they will be granted persisted uri access to all slices of this + * provider. + * + * @param autoGrantPermissions List of permissions that holders are auto-granted access + * to slices. + */ + public SliceProvider(@NonNull String... autoGrantPermissions) { + mAutoGrantPermissions = autoGrantPermissions; + } + + public SliceProvider() { + mAutoGrantPermissions = new String[0]; + } + @Override public void attachInfo(Context context, ProviderInfo info) { super.attachInfo(context, info); @@ -402,7 +423,7 @@ public abstract class SliceProvider extends ContentProvider { : getContext().getPackageManager().getNameForUid(callingUid); try { mSliceManager.enforceSlicePermission(sliceUri, pkg, - callingPid, callingUid); + callingPid, callingUid, mAutoGrantPermissions); } catch (SecurityException e) { return createPermissionSlice(getContext(), sliceUri, pkg); } diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java index 0b7d9d02f1cb..fd0b6f1eb457 100644 --- a/services/core/java/com/android/server/slice/SliceManagerService.java +++ b/services/core/java/com/android/server/slice/SliceManagerService.java @@ -168,7 +168,8 @@ public class SliceManagerService extends ISliceManager.Stub { } @Override - public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token) throws RemoteException { + public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token) + throws RemoteException { verifyCaller(pkg); enforceAccess(pkg, uri); int user = Binder.getCallingUserHandle().getIdentifier(); @@ -210,7 +211,8 @@ public class SliceManagerService extends ISliceManager.Stub { } @Override - public int checkSlicePermission(Uri uri, String pkg, int pid, int uid) throws RemoteException { + public int checkSlicePermission(Uri uri, String pkg, int pid, int uid, + String[] autoGrantPermissions) throws RemoteException { if (mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == PERMISSION_GRANTED) { return SliceManager.PERMISSION_GRANTED; @@ -218,6 +220,11 @@ public class SliceManagerService extends ISliceManager.Stub { if (hasFullSliceAccess(pkg, UserHandle.getUserId(uid))) { return SliceManager.PERMISSION_GRANTED; } + for (String perm : autoGrantPermissions) { + if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) { + return SliceManager.PERMISSION_USER_GRANTED; + } + } synchronized (mLock) { if (mUserGrants.contains(new SliceGrant(uri, pkg, UserHandle.getUserId(uid)))) { return SliceManager.PERMISSION_USER_GRANTED; diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java index 1073a800527a..5e2a36486972 100644 --- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java @@ -15,8 +15,10 @@ package com.android.server.slice; import static android.content.ContentProvider.maybeAddUserId; +import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -35,9 +37,11 @@ import android.content.pm.PackageManagerInternal; import android.net.Uri; import android.os.Binder; import android.os.IBinder; +import android.os.Process; import android.os.RemoteException; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; +import android.testing.TestableContext; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; @@ -63,6 +67,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase { private SliceManagerService mService; private PinnedSliceState mCreatedSliceState; private IBinder mToken = new Binder(); + private TestableContext mContextSpy; @Before public void setup() { @@ -72,7 +77,8 @@ public class SliceManagerServiceTest extends UiServiceTestCase { mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); mContext.getTestablePermissions().setPermission(TEST_URI, PERMISSION_GRANTED); - mService = spy(new SliceManagerService(mContext, TestableLooper.get(this).getLooper())); + mContextSpy = spy(mContext); + mService = spy(new SliceManagerService(mContextSpy, TestableLooper.get(this).getLooper())); mCreatedSliceState = mock(PinnedSliceState.class); doReturn(mCreatedSliceState).when(mService).createPinnedSlice(eq(TEST_URI), anyString()); } @@ -103,4 +109,23 @@ public class SliceManagerServiceTest extends UiServiceTestCase { verify(mCreatedSliceState, never()).destroy(); } + @Test + public void testCheckAutoGrantPermissions() throws RemoteException { + String[] testPerms = new String[] { + "perm1", + "perm2", + }; + when(mContextSpy.checkUriPermission(any(), anyInt(), anyInt(), anyInt())) + .thenReturn(PERMISSION_DENIED); + when(mContextSpy.checkPermission("perm1", Process.myPid(), Process.myUid())) + .thenReturn(PERMISSION_DENIED); + when(mContextSpy.checkPermission("perm2", Process.myPid(), Process.myUid())) + .thenReturn(PERMISSION_GRANTED); + mService.checkSlicePermission(TEST_URI, mContext.getPackageName(), Process.myPid(), + Process.myUid(), testPerms); + + verify(mContextSpy).checkPermission(eq("perm1"), eq(Process.myPid()), eq(Process.myUid())); + verify(mContextSpy).checkPermission(eq("perm2"), eq(Process.myPid()), eq(Process.myUid())); + } + }
\ No newline at end of file |