Merge "Allow bindServiceAsUser without _FULL if same app"
This commit is contained in:
@@ -10823,7 +10823,7 @@ package android.content {
|
||||
method public boolean bindIsolatedService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
|
||||
method public abstract boolean bindService(@RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int);
|
||||
method public boolean bindService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
|
||||
method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.INTERACT_ACROSS_PROFILES}) public boolean bindServiceAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle);
|
||||
method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL", android.Manifest.permission.INTERACT_ACROSS_PROFILES}, conditional=true) public boolean bindServiceAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle);
|
||||
method @CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)") public abstract int checkCallingOrSelfPermission(@NonNull String);
|
||||
method @CheckResult(suggest="#enforceCallingOrSelfUriPermission(Uri,int,String)") public abstract int checkCallingOrSelfUriPermission(android.net.Uri, int);
|
||||
method @NonNull public int[] checkCallingOrSelfUriPermissions(@NonNull java.util.List<android.net.Uri>, int);
|
||||
|
||||
@@ -71,6 +71,9 @@ public abstract class ActivityManagerInternal {
|
||||
}
|
||||
|
||||
// Access modes for handleIncomingUser.
|
||||
/**
|
||||
* Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_USERS}.
|
||||
*/
|
||||
public static final int ALLOW_NON_FULL = 0;
|
||||
/**
|
||||
* Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
|
||||
@@ -78,13 +81,18 @@ public abstract class ActivityManagerInternal {
|
||||
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
|
||||
*/
|
||||
public static final int ALLOW_NON_FULL_IN_PROFILE = 1;
|
||||
/**
|
||||
* Allows access to a caller only if it has the full
|
||||
* {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
|
||||
*/
|
||||
public static final int ALLOW_FULL_ONLY = 2;
|
||||
/**
|
||||
* Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
|
||||
* or {@link android.Manifest.permission#INTERACT_ACROSS_USERS} if in the same profile group.
|
||||
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
|
||||
* if in the same profile group.
|
||||
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS} is required and suffices
|
||||
* as in {@link #ALLOW_NON_FULL}.
|
||||
*/
|
||||
public static final int ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE = 3;
|
||||
public static final int ALLOW_PROFILES_OR_NON_FULL = 3;
|
||||
|
||||
/**
|
||||
* Returns profile information in free form string in two separate strings.
|
||||
|
||||
@@ -3601,10 +3601,18 @@ public abstract class Context {
|
||||
* Binds to a service in the given {@code user} in the same manner as
|
||||
* {@link #bindService(Intent, ServiceConnection, int)}.
|
||||
*
|
||||
* <p>If the given {@code user} is in the same profile group and the target package is the
|
||||
* same as the caller, {@code android.Manifest.permission.INTERACT_ACROSS_PROFILES} is
|
||||
* sufficient. Otherwise, requires {@code android.Manifest.permission.INTERACT_ACROSS_USERS}
|
||||
* for interacting with other users.
|
||||
* <p>Requires that one of the following conditions are met:
|
||||
* <ul>
|
||||
* <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}</li>
|
||||
* <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_USERS} and is the same
|
||||
* package as the {@code service} (determined by its component's package) and the Android
|
||||
* version is at least {@link android.os.Build.VERSION_CODES#S}</li>
|
||||
* <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_USERS} and is in same
|
||||
* profile group as the given {@code user}</li>
|
||||
* <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_PROFILES} and is in same
|
||||
* profile group as the given {@code user} and is the same package as the {@code service}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param service Identifies the service to connect to. The Intent must
|
||||
* specify an explicit component name.
|
||||
@@ -3626,8 +3634,9 @@ public abstract class Context {
|
||||
@SuppressWarnings("unused")
|
||||
@RequiresPermission(anyOf = {
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS,
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
|
||||
android.Manifest.permission.INTERACT_ACROSS_PROFILES
|
||||
})
|
||||
}, conditional = true)
|
||||
public boolean bindServiceAsUser(
|
||||
@NonNull @RequiresPermission Intent service, @NonNull ServiceConnection conn, int flags,
|
||||
@NonNull UserHandle user) {
|
||||
@@ -3640,7 +3649,11 @@ public abstract class Context {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
|
||||
@RequiresPermission(anyOf = {
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS,
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
|
||||
android.Manifest.permission.INTERACT_ACROSS_PROFILES
|
||||
}, conditional = true)
|
||||
@UnsupportedAppUsage(trackingBug = 136728678)
|
||||
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
|
||||
Handler handler, UserHandle user) {
|
||||
|
||||
@@ -3472,11 +3472,9 @@ public final class ActiveServices {
|
||||
}
|
||||
|
||||
private int getAllowMode(Intent service, @Nullable String callingPackage) {
|
||||
if (callingPackage == null || service.getComponent() == null) {
|
||||
return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
|
||||
}
|
||||
if (callingPackage.equals(service.getComponent().getPackageName())) {
|
||||
return ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
|
||||
if (callingPackage != null && service.getComponent() != null
|
||||
&& callingPackage.equals(service.getComponent().getPackageName())) {
|
||||
return ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
|
||||
} else {
|
||||
return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM;
|
||||
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
|
||||
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
|
||||
import static android.app.ActivityManager.USER_OP_SUCCESS;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
|
||||
import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED;
|
||||
import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
|
||||
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
|
||||
@@ -2153,11 +2153,10 @@ class UserController implements Handler.Callback {
|
||||
callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
|
||||
// If the caller does not have either permission, they are always doomed.
|
||||
allow = false;
|
||||
} else if (allowMode == ALLOW_NON_FULL) {
|
||||
} else if (allowMode == ALLOW_NON_FULL || allowMode == ALLOW_PROFILES_OR_NON_FULL) {
|
||||
// We are blanket allowing non-full access, you lucky caller!
|
||||
allow = true;
|
||||
} else if (allowMode == ALLOW_NON_FULL_IN_PROFILE
|
||||
|| allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
|
||||
} else if (allowMode == ALLOW_NON_FULL_IN_PROFILE) {
|
||||
// We may or may not allow this depending on whether the two users are
|
||||
// in the same profile.
|
||||
allow = isSameProfileGroup;
|
||||
@@ -2184,12 +2183,13 @@ class UserController implements Handler.Callback {
|
||||
builder.append("; this requires ");
|
||||
builder.append(INTERACT_ACROSS_USERS_FULL);
|
||||
if (allowMode != ALLOW_FULL_ONLY) {
|
||||
if (allowMode == ALLOW_NON_FULL || isSameProfileGroup) {
|
||||
if (allowMode == ALLOW_NON_FULL
|
||||
|| allowMode == ALLOW_PROFILES_OR_NON_FULL
|
||||
|| (allowMode == ALLOW_NON_FULL_IN_PROFILE && isSameProfileGroup)) {
|
||||
builder.append(" or ");
|
||||
builder.append(INTERACT_ACROSS_USERS);
|
||||
}
|
||||
if (isSameProfileGroup
|
||||
&& allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
|
||||
if (isSameProfileGroup && allowMode == ALLOW_PROFILES_OR_NON_FULL) {
|
||||
builder.append(" or ");
|
||||
builder.append(INTERACT_ACROSS_PROFILES);
|
||||
}
|
||||
@@ -2216,19 +2216,14 @@ class UserController implements Handler.Callback {
|
||||
private boolean canInteractWithAcrossProfilesPermission(
|
||||
int allowMode, boolean isSameProfileGroup, int callingPid, int callingUid,
|
||||
String callingPackage) {
|
||||
if (allowMode != ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
|
||||
if (allowMode != ALLOW_PROFILES_OR_NON_FULL) {
|
||||
return false;
|
||||
}
|
||||
if (!isSameProfileGroup) {
|
||||
return false;
|
||||
}
|
||||
return PermissionChecker.PERMISSION_GRANTED
|
||||
== PermissionChecker.checkPermissionForPreflight(
|
||||
mInjector.getContext(),
|
||||
INTERACT_ACROSS_PROFILES,
|
||||
callingPid,
|
||||
callingUid,
|
||||
callingPackage);
|
||||
return mInjector.checkPermissionForPreflight(INTERACT_ACROSS_PROFILES, callingPid,
|
||||
callingUid, callingPackage);
|
||||
}
|
||||
|
||||
int unsafeConvertIncomingUser(@UserIdInt int userId) {
|
||||
@@ -3157,6 +3152,12 @@ class UserController implements Handler.Callback {
|
||||
return mService.checkComponentPermission(permission, pid, uid, owningUid, exported);
|
||||
}
|
||||
|
||||
boolean checkPermissionForPreflight(String permission, int pid, int uid, String pkg) {
|
||||
return PermissionChecker.PERMISSION_GRANTED
|
||||
== PermissionChecker.checkPermissionForPreflight(
|
||||
getContext(), permission, pid, uid, pkg);
|
||||
}
|
||||
|
||||
protected void startHomeActivity(@UserIdInt int userId, String reason) {
|
||||
mService.mAtmInternal.startHomeActivity(userId, reason);
|
||||
}
|
||||
@@ -3234,7 +3235,7 @@ class UserController implements Handler.Callback {
|
||||
mService.mAtmInternal.clearLockedTasks(reason);
|
||||
}
|
||||
|
||||
protected boolean isCallerRecents(int callingUid) {
|
||||
boolean isCallerRecents(int callingUid) {
|
||||
return mService.mAtmInternal.isCallerRecents(callingUid);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,13 @@
|
||||
|
||||
package com.android.server.am;
|
||||
|
||||
import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
|
||||
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
|
||||
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
|
||||
|
||||
@@ -64,6 +71,7 @@ import android.app.KeyguardManager;
|
||||
import android.content.Context;
|
||||
import android.content.IIntentReceiver;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.pm.UserInfo.UserInfoFlag;
|
||||
import android.os.Binder;
|
||||
@@ -617,6 +625,100 @@ public class UserControllerTest {
|
||||
assertProfileLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* expectLocking= */ true);
|
||||
}
|
||||
|
||||
/** Tests handleIncomingUser() for a variety of permissions and situations. */
|
||||
@Test
|
||||
public void testHandleIncomingUser() throws Exception {
|
||||
final UserInfo user1a = new UserInfo(111, "user1a", 0);
|
||||
final UserInfo user1b = new UserInfo(112, "user1b", 0);
|
||||
final UserInfo user2 = new UserInfo(113, "user2", 0);
|
||||
// user1a and user2b are in the same profile group; user2 is in a different one.
|
||||
user1a.profileGroupId = 5;
|
||||
user1b.profileGroupId = 5;
|
||||
user2.profileGroupId = 6;
|
||||
|
||||
final List<UserInfo> users = Arrays.asList(user1a, user1b, user2);
|
||||
when(mInjector.mUserManagerMock.getUsers(false)).thenReturn(users);
|
||||
mUserController.onSystemReady(); // To set the profileGroupIds in UserController.
|
||||
|
||||
|
||||
// Has INTERACT_ACROSS_USERS_FULL.
|
||||
when(mInjector.checkComponentPermission(
|
||||
eq(INTERACT_ACROSS_USERS_FULL), anyInt(), anyInt(), anyInt(), anyBoolean()))
|
||||
.thenReturn(PackageManager.PERMISSION_GRANTED);
|
||||
when(mInjector.checkComponentPermission(
|
||||
eq(INTERACT_ACROSS_USERS), anyInt(), anyInt(), anyInt(), anyBoolean()))
|
||||
.thenReturn(PackageManager.PERMISSION_DENIED);
|
||||
when(mInjector.checkPermissionForPreflight(
|
||||
eq(INTERACT_ACROSS_PROFILES), anyInt(), anyInt(), any())).thenReturn(false);
|
||||
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL, true);
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL_IN_PROFILE, true);
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_FULL_ONLY, true);
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_PROFILES_OR_NON_FULL, true);
|
||||
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL, true);
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL_IN_PROFILE, true);
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_FULL_ONLY, true);
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_PROFILES_OR_NON_FULL, true);
|
||||
|
||||
|
||||
// Has INTERACT_ACROSS_USERS.
|
||||
when(mInjector.checkComponentPermission(
|
||||
eq(INTERACT_ACROSS_USERS_FULL), anyInt(), anyInt(), anyInt(), anyBoolean()))
|
||||
.thenReturn(PackageManager.PERMISSION_DENIED);
|
||||
when(mInjector.checkComponentPermission(
|
||||
eq(INTERACT_ACROSS_USERS), anyInt(), anyInt(), anyInt(), anyBoolean()))
|
||||
.thenReturn(PackageManager.PERMISSION_GRANTED);
|
||||
when(mInjector.checkPermissionForPreflight(
|
||||
eq(INTERACT_ACROSS_PROFILES), anyInt(), anyInt(), any())).thenReturn(false);
|
||||
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL, true);
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL_IN_PROFILE, false);
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_FULL_ONLY, false);
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_PROFILES_OR_NON_FULL, true);
|
||||
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL, true);
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL_IN_PROFILE, true);
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_FULL_ONLY, false);
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_PROFILES_OR_NON_FULL, true);
|
||||
|
||||
|
||||
// Has INTERACT_ACROSS_PROFILES.
|
||||
when(mInjector.checkComponentPermission(
|
||||
eq(INTERACT_ACROSS_USERS_FULL), anyInt(), anyInt(), anyInt(), anyBoolean()))
|
||||
.thenReturn(PackageManager.PERMISSION_DENIED);
|
||||
when(mInjector.checkComponentPermission(
|
||||
eq(INTERACT_ACROSS_USERS), anyInt(), anyInt(), anyInt(), anyBoolean()))
|
||||
.thenReturn(PackageManager.PERMISSION_DENIED);
|
||||
when(mInjector.checkPermissionForPreflight(
|
||||
eq(INTERACT_ACROSS_PROFILES), anyInt(), anyInt(), any())).thenReturn(true);
|
||||
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL, false);
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL_IN_PROFILE, false);
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_FULL_ONLY, false);
|
||||
checkHandleIncomingUser(user1a.id, user2.id, ALLOW_PROFILES_OR_NON_FULL, false);
|
||||
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL, false);
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL_IN_PROFILE, false);
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_FULL_ONLY, false);
|
||||
checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_PROFILES_OR_NON_FULL, true);
|
||||
}
|
||||
|
||||
private void checkHandleIncomingUser(int fromUser, int toUser, int allowMode, boolean pass) {
|
||||
final int pid = 100;
|
||||
final int uid = fromUser * UserHandle.PER_USER_RANGE + 34567 + fromUser;
|
||||
final String name = "whatever";
|
||||
final String pkg = "some.package";
|
||||
final boolean allowAll = false;
|
||||
|
||||
if (pass) {
|
||||
mUserController.handleIncomingUser(pid, uid, toUser, allowAll, allowMode, name, pkg);
|
||||
} else {
|
||||
assertThrows(SecurityException.class, () -> mUserController.handleIncomingUser(
|
||||
pid, uid, toUser, allowAll, allowMode, name, pkg));
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpAndStartUserInBackground(int userId) throws Exception {
|
||||
setUpUser(userId, 0);
|
||||
mUserController.startUser(userId, /* foreground= */ false);
|
||||
@@ -783,6 +885,23 @@ public class UserControllerTest {
|
||||
return PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
int checkComponentPermission(String permission, int pid, int uid, int owner, boolean exp) {
|
||||
Log.i(TAG, "checkComponentPermission " + permission);
|
||||
return PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean checkPermissionForPreflight(String permission, int pid, int uid, String pkg) {
|
||||
Log.i(TAG, "checkPermissionForPreflight " + permission);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isCallerRecents(int uid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
WindowManagerService getWindowManager() {
|
||||
return mWindowManagerMock;
|
||||
|
||||
Reference in New Issue
Block a user