Merge "Add auto-grant permission slice API" into pi-dev

am: 4ced90cb12

Change-Id: I1cafb654553e62e8720d6c8b101328d5227dc545
This commit is contained in:
Jason Monk
2018-03-30 21:48:11 +00:00
committed by android-build-merger
6 changed files with 65 additions and 7 deletions

View File

@@ -7304,6 +7304,7 @@ package android.app.slice {
} }
public abstract class SliceProvider extends android.content.ContentProvider { public abstract class SliceProvider extends android.content.ContentProvider {
ctor public SliceProvider(java.lang.String...);
ctor public SliceProvider(); ctor public SliceProvider();
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public final java.lang.String getType(android.net.Uri); method public final java.lang.String getType(android.net.Uri);

View File

@@ -25,7 +25,8 @@ interface ISliceManager {
void unpinSlice(String pkg, in Uri uri, in IBinder token); void unpinSlice(String pkg, in Uri uri, in IBinder token);
boolean hasSliceAccess(String pkg); boolean hasSliceAccess(String pkg);
SliceSpec[] getPinnedSpecs(in Uri uri, 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); void grantPermissionFromUser(in Uri uri, String pkg, String callingPkg, boolean allSlices);
Uri[] getPinnedSlices(String pkg); Uri[] getPinnedSlices(String pkg);

View File

@@ -404,7 +404,8 @@ public class SliceManager {
* Does the permission check to see if a caller has access to a specific slice. * Does the permission check to see if a caller has access to a specific slice.
* @hide * @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 { try {
if (UserHandle.isSameApp(uid, Process.myUid())) { if (UserHandle.isSameApp(uid, Process.myUid())) {
return; return;
@@ -412,7 +413,7 @@ public class SliceManager {
if (pkg == null) { if (pkg == null) {
throw new SecurityException("No pkg specified"); 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) { if (result == PERMISSION_DENIED) {
throw new SecurityException("User " + uid + " does not have slice permission for " throw new SecurityException("User " + uid + " does not have slice permission for "
+ uri + "."); + uri + ".");
@@ -424,6 +425,8 @@ public class SliceManager {
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_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) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();

View File

@@ -149,10 +149,31 @@ public abstract class SliceProvider extends ContentProvider {
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
private static final long SLICE_BIND_ANR = 2000; private static final long SLICE_BIND_ANR = 2000;
private final String[] mAutoGrantPermissions;
private String mCallback; private String mCallback;
private SliceManager mSliceManager; 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 @Override
public void attachInfo(Context context, ProviderInfo info) { public void attachInfo(Context context, ProviderInfo info) {
super.attachInfo(context, info); super.attachInfo(context, info);
@@ -402,7 +423,7 @@ public abstract class SliceProvider extends ContentProvider {
: getContext().getPackageManager().getNameForUid(callingUid); : getContext().getPackageManager().getNameForUid(callingUid);
try { try {
mSliceManager.enforceSlicePermission(sliceUri, pkg, mSliceManager.enforceSlicePermission(sliceUri, pkg,
callingPid, callingUid); callingPid, callingUid, mAutoGrantPermissions);
} catch (SecurityException e) { } catch (SecurityException e) {
return createPermissionSlice(getContext(), sliceUri, pkg); return createPermissionSlice(getContext(), sliceUri, pkg);
} }

View File

@@ -168,7 +168,8 @@ public class SliceManagerService extends ISliceManager.Stub {
} }
@Override @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); verifyCaller(pkg);
enforceAccess(pkg, uri); enforceAccess(pkg, uri);
int user = Binder.getCallingUserHandle().getIdentifier(); int user = Binder.getCallingUserHandle().getIdentifier();
@@ -210,7 +211,8 @@ public class SliceManagerService extends ISliceManager.Stub {
} }
@Override @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) if (mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
== PERMISSION_GRANTED) { == PERMISSION_GRANTED) {
return SliceManager.PERMISSION_GRANTED; return SliceManager.PERMISSION_GRANTED;
@@ -218,6 +220,11 @@ public class SliceManagerService extends ISliceManager.Stub {
if (hasFullSliceAccess(pkg, UserHandle.getUserId(uid))) { if (hasFullSliceAccess(pkg, UserHandle.getUserId(uid))) {
return SliceManager.PERMISSION_GRANTED; return SliceManager.PERMISSION_GRANTED;
} }
for (String perm : autoGrantPermissions) {
if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
return SliceManager.PERMISSION_USER_GRANTED;
}
}
synchronized (mLock) { synchronized (mLock) {
if (mUserGrants.contains(new SliceGrant(uri, pkg, UserHandle.getUserId(uid)))) { if (mUserGrants.contains(new SliceGrant(uri, pkg, UserHandle.getUserId(uid)))) {
return SliceManager.PERMISSION_USER_GRANTED; return SliceManager.PERMISSION_USER_GRANTED;

View File

@@ -15,8 +15,10 @@
package com.android.server.slice; package com.android.server.slice;
import static android.content.ContentProvider.maybeAddUserId; import static android.content.ContentProvider.maybeAddUserId;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED; 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.anyInt;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
@@ -35,9 +37,11 @@ import android.content.pm.PackageManagerInternal;
import android.net.Uri; import android.net.Uri;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.testing.TestableLooper; import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper; import android.testing.TestableLooper.RunWithLooper;
@@ -63,6 +67,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
private SliceManagerService mService; private SliceManagerService mService;
private PinnedSliceState mCreatedSliceState; private PinnedSliceState mCreatedSliceState;
private IBinder mToken = new Binder(); private IBinder mToken = new Binder();
private TestableContext mContextSpy;
@Before @Before
public void setup() { public void setup() {
@@ -72,7 +77,8 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
mContext.getTestablePermissions().setPermission(TEST_URI, PERMISSION_GRANTED); 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); mCreatedSliceState = mock(PinnedSliceState.class);
doReturn(mCreatedSliceState).when(mService).createPinnedSlice(eq(TEST_URI), anyString()); doReturn(mCreatedSliceState).when(mService).createPinnedSlice(eq(TEST_URI), anyString());
} }
@@ -103,4 +109,23 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
verify(mCreatedSliceState, never()).destroy(); 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()));
}
} }