Move getUserSwitchability from UserManager to UserManagerService.
UserManager.getUserSwitchability was calling telecomManager.isInCall method to see whether there is an ongoing phone call. Since the call was made from client side, it was causing a SecurityException when switcing users via adb command and breaking CtsMultiUserHostTestCases tests. This CL moves all the logic from UserManager to UserManagerService, and calls telecomManager.isInCall() with Binder.clearCallingIdentity. Bug: 257538981 Bug: 261505371 Test: atest CtsMultiUserHostTestCases Change-Id: Idfca1fcb89688d08878b908ceed9c64f1e7091d3
This commit is contained in:
@@ -10221,7 +10221,7 @@ package android.os {
|
|||||||
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
|
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
|
||||||
method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public int getUserRestrictionSource(String, android.os.UserHandle);
|
method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public int getUserRestrictionSource(String, android.os.UserHandle);
|
||||||
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
|
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
|
||||||
method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability();
|
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public int getUserSwitchability();
|
||||||
method @NonNull @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.MANAGE_USERS"}) public java.util.Set<android.os.UserHandle> getVisibleUsers();
|
method @NonNull @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.MANAGE_USERS"}) public java.util.Set<android.os.UserHandle> getVisibleUsers();
|
||||||
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean hasRestrictedProfiles();
|
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean hasRestrictedProfiles();
|
||||||
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
|
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ interface IUserManager {
|
|||||||
String getUserAccount(int userId);
|
String getUserAccount(int userId);
|
||||||
void setUserAccount(int userId, String accountName);
|
void setUserAccount(int userId, String accountName);
|
||||||
long getUserCreationTime(int userId);
|
long getUserCreationTime(int userId);
|
||||||
|
int getUserSwitchability(int userId);
|
||||||
boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable, int mUserId);
|
boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable, int mUserId);
|
||||||
boolean isRestricted(int userId);
|
boolean isRestricted(int userId);
|
||||||
boolean canHaveRestrictedProfile(int userId);
|
boolean canHaveRestrictedProfile(int userId);
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ import android.graphics.Rect;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.telecom.TelecomManager;
|
|
||||||
import android.util.AndroidException;
|
import android.util.AndroidException;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -1748,7 +1747,7 @@ public class UserManager {
|
|||||||
public static final int SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED = 1 << 2;
|
public static final int SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED = 1 << 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Result returned in {@link #getUserSwitchability()} indicating user swichability.
|
* Result returned in {@link #getUserSwitchability()} indicating user switchability.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@@ -2128,20 +2127,16 @@ public class UserManager {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@RequiresPermission(allOf = {
|
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
|
||||||
Manifest.permission.READ_PHONE_STATE,
|
android.Manifest.permission.INTERACT_ACROSS_USERS})
|
||||||
Manifest.permission.MANAGE_USERS}, // Can be INTERACT_ACROSS_USERS instead.
|
|
||||||
conditional = true)
|
|
||||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||||
@UserHandleAware
|
@UserHandleAware
|
||||||
public boolean canSwitchUsers() {
|
public boolean canSwitchUsers() {
|
||||||
boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
|
try {
|
||||||
mContext.getContentResolver(),
|
return mService.getUserSwitchability(mUserId) == SWITCHABILITY_STATUS_OK;
|
||||||
Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
|
} catch (RemoteException re) {
|
||||||
boolean isSystemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM);
|
throw re.rethrowFromSystemServer();
|
||||||
boolean isUserSwitchDisallowed = hasUserRestrictionForUser(DISALLOW_USER_SWITCH, mUserId);
|
}
|
||||||
return (allowUserSwitchingWhenSystemUserLocked || isSystemUserUnlocked) && !inCall()
|
|
||||||
&& !isUserSwitchDisallowed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2156,9 +2151,8 @@ public class UserManager {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@SystemApi
|
@SystemApi
|
||||||
@RequiresPermission(allOf = {Manifest.permission.READ_PHONE_STATE,
|
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
|
||||||
android.Manifest.permission.MANAGE_USERS,
|
android.Manifest.permission.INTERACT_ACROSS_USERS})
|
||||||
android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
|
|
||||||
@UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU)
|
@UserHandleAware(enabledSinceTargetSdkVersion = Build.VERSION_CODES.TIRAMISU)
|
||||||
public @UserSwitchabilityResult int getUserSwitchability() {
|
public @UserSwitchabilityResult int getUserSwitchability() {
|
||||||
return getUserSwitchability(UserHandle.of(getContextUserIfAppropriate()));
|
return getUserSwitchability(UserHandle.of(getContextUserIfAppropriate()));
|
||||||
@@ -2175,31 +2169,14 @@ public class UserManager {
|
|||||||
* @return A {@link UserSwitchabilityResult} flag indicating if the user is switchable.
|
* @return A {@link UserSwitchabilityResult} flag indicating if the user is switchable.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@RequiresPermission(allOf = {Manifest.permission.READ_PHONE_STATE,
|
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
|
||||||
android.Manifest.permission.MANAGE_USERS,
|
android.Manifest.permission.INTERACT_ACROSS_USERS})
|
||||||
android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
|
|
||||||
public @UserSwitchabilityResult int getUserSwitchability(UserHandle userHandle) {
|
public @UserSwitchabilityResult int getUserSwitchability(UserHandle userHandle) {
|
||||||
int flags = SWITCHABILITY_STATUS_OK;
|
try {
|
||||||
if (inCall()) {
|
return mService.getUserSwitchability(userHandle.getIdentifier());
|
||||||
flags |= SWITCHABILITY_STATUS_USER_IN_CALL;
|
} catch (RemoteException re) {
|
||||||
|
throw re.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
if (hasUserRestrictionForUser(DISALLOW_USER_SWITCH, userHandle)) {
|
|
||||||
flags |= SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// System User is always unlocked in Headless System User Mode, so ignore this flag
|
|
||||||
if (!isHeadlessSystemUserMode()) {
|
|
||||||
final boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
|
|
||||||
mContext.getContentResolver(),
|
|
||||||
Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
|
|
||||||
final boolean systemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM);
|
|
||||||
|
|
||||||
if (!allowUserSwitchingWhenSystemUserLocked && !systemUserUnlocked) {
|
|
||||||
flags |= SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return flags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5614,11 +5591,6 @@ public class UserManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean inCall() {
|
|
||||||
final TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
|
|
||||||
return telecomManager != null && telecomManager.isInCall();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cache key for anything that assumes that userIds cannot be re-used without rebooting. */
|
/* Cache key for anything that assumes that userIds cannot be re-used without rebooting. */
|
||||||
private static final String CACHE_KEY_STATIC_USER_PROPERTIES = "cache_key.static_user_props";
|
private static final String CACHE_KEY_STATIC_USER_PROPERTIES = "cache_key.static_user_props";
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ import android.os.storage.StorageManagerInternal;
|
|||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.service.voice.VoiceInteractionManagerInternal;
|
import android.service.voice.VoiceInteractionManagerInternal;
|
||||||
import android.stats.devicepolicy.DevicePolicyEnums;
|
import android.stats.devicepolicy.DevicePolicyEnums;
|
||||||
|
import android.telecom.TelecomManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
@@ -128,7 +129,6 @@ import com.android.server.SystemService;
|
|||||||
import com.android.server.am.UserState;
|
import com.android.server.am.UserState;
|
||||||
import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
|
import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
|
||||||
import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
|
import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
|
||||||
import com.android.server.pm.UserManagerInternal.UserVisibilityListener;
|
|
||||||
import com.android.server.storage.DeviceStorageMonitorInternal;
|
import com.android.server.storage.DeviceStorageMonitorInternal;
|
||||||
import com.android.server.utils.Slogf;
|
import com.android.server.utils.Slogf;
|
||||||
import com.android.server.utils.TimingsTraceAndSlog;
|
import com.android.server.utils.TimingsTraceAndSlog;
|
||||||
@@ -1970,6 +1970,63 @@ public class UserManagerService extends IUserManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether switching users is currently allowed for the provided user.
|
||||||
|
* <p>
|
||||||
|
* Switching users is not allowed in the following cases:
|
||||||
|
* <li>the user is in a phone call</li>
|
||||||
|
* <li>{@link UserManager#DISALLOW_USER_SWITCH} is set</li>
|
||||||
|
* <li>system user hasn't been unlocked yet</li>
|
||||||
|
*
|
||||||
|
* @return A {@link UserManager.UserSwitchabilityResult} flag indicating if the user is
|
||||||
|
* switchable.
|
||||||
|
*/
|
||||||
|
public @UserManager.UserSwitchabilityResult int getUserSwitchability(int userId) {
|
||||||
|
checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "getUserSwitchability");
|
||||||
|
|
||||||
|
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
|
||||||
|
t.traceBegin("getUserSwitchability-" + userId);
|
||||||
|
|
||||||
|
int flags = UserManager.SWITCHABILITY_STATUS_OK;
|
||||||
|
|
||||||
|
t.traceBegin("TM.isInCall");
|
||||||
|
final long identity = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
final TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
|
||||||
|
if (telecomManager != null && telecomManager.isInCall()) {
|
||||||
|
flags |= UserManager.SWITCHABILITY_STATUS_USER_IN_CALL;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
|
}
|
||||||
|
t.traceEnd();
|
||||||
|
|
||||||
|
t.traceBegin("hasUserRestriction-DISALLOW_USER_SWITCH");
|
||||||
|
if (mLocalService.hasUserRestriction(DISALLOW_USER_SWITCH, userId)) {
|
||||||
|
flags |= UserManager.SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED;
|
||||||
|
}
|
||||||
|
t.traceEnd();
|
||||||
|
|
||||||
|
// System User is always unlocked in Headless System User Mode, so ignore this flag
|
||||||
|
if (!isHeadlessSystemUserMode()) {
|
||||||
|
t.traceBegin("getInt-ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED");
|
||||||
|
final boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
|
||||||
|
mContext.getContentResolver(),
|
||||||
|
Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
|
||||||
|
t.traceEnd();
|
||||||
|
t.traceBegin("isUserUnlocked-USER_SYSTEM");
|
||||||
|
final boolean systemUserUnlocked = mLocalService.isUserUnlocked(UserHandle.USER_SYSTEM);
|
||||||
|
t.traceEnd();
|
||||||
|
|
||||||
|
if (!allowUserSwitchingWhenSystemUserLocked && !systemUserUnlocked) {
|
||||||
|
flags |= UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.traceEnd();
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean isUserSwitcherEnabled(@UserIdInt int mUserId) {
|
boolean isUserSwitcherEnabled(@UserIdInt int mUserId) {
|
||||||
boolean multiUserSettingOn = Settings.Global.getInt(mContext.getContentResolver(),
|
boolean multiUserSettingOn = Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
|
|||||||
Reference in New Issue
Block a user