From e2062736eced6afdaa40b557f8c32461ae896020 Mon Sep 17 00:00:00 2001 From: Yasin Kilicdere Date: Wed, 7 Dec 2022 12:42:53 +0000 Subject: [PATCH] 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 Fixes: 260184263 Test: atest CtsMultiUserHostTestCases Merged-In: Idfca1fcb89688d08878b908ceed9c64f1e7091d3 Change-Id: Idfca1fcb89688d08878b908ceed9c64f1e7091d3 (cherry picked from commit 2f17ef912ee8cc321d54b08acb119d1ad641b756) --- core/java/android/os/IUserManager.aidl | 1 + core/java/android/os/UserManager.java | 56 +++++------------- .../android/server/pm/UserManagerService.java | 58 +++++++++++++++++++ 3 files changed, 72 insertions(+), 43 deletions(-) diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index e1d15defad381..125bdaf07b908 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -74,6 +74,7 @@ interface IUserManager { String getUserAccount(int userId); void setUserAccount(int userId, String accountName); long getUserCreationTime(int userId); + int getUserSwitchability(int userId); boolean isUserSwitcherEnabled(int mUserId); boolean isRestricted(int userId); boolean canHaveRestrictedProfile(int userId); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 5487a12038334..46fff2bfc9221 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -58,7 +58,6 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.location.LocationManager; import android.provider.Settings; -import android.telephony.TelephonyManager; import android.util.AndroidException; import android.util.ArraySet; import android.util.Log; @@ -1670,7 +1669,7 @@ public class UserManager { 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 */ @Retention(RetentionPolicy.SOURCE) @@ -2037,25 +2036,16 @@ public class UserManager { * @hide */ @Deprecated - @RequiresPermission(allOf = { - Manifest.permission.READ_PHONE_STATE, - Manifest.permission.MANAGE_USERS}, // Can be INTERACT_ACROSS_USERS instead. - conditional = true) + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.INTERACT_ACROSS_USERS}) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @UserHandleAware public boolean canSwitchUsers() { - boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt( - mContext.getContentResolver(), - Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0; - boolean isSystemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM); - boolean inCall = false; - TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class); - if (telephonyManager != null) { - inCall = telephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE; + try { + return mService.getUserSwitchability(mUserId) == SWITCHABILITY_STATUS_OK; + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); } - boolean isUserSwitchDisallowed = hasUserRestrictionForUser(DISALLOW_USER_SWITCH, mUserId); - return (allowUserSwitchingWhenSystemUserLocked || isSystemUserUnlocked) && !inCall - && !isUserSwitchDisallowed; } /** @@ -2089,34 +2079,14 @@ public class UserManager { * @return A {@link UserSwitchabilityResult} flag indicating if the user is switchable. * @hide */ - @RequiresPermission(allOf = {Manifest.permission.READ_PHONE_STATE, - android.Manifest.permission.MANAGE_USERS, - android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.INTERACT_ACROSS_USERS}) public @UserSwitchabilityResult int getUserSwitchability(UserHandle userHandle) { - final TelephonyManager tm = - (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); - - int flags = SWITCHABILITY_STATUS_OK; - if (tm.getCallState() != TelephonyManager.CALL_STATE_IDLE) { - flags |= SWITCHABILITY_STATUS_USER_IN_CALL; + try { + return mService.getUserSwitchability(userHandle.getIdentifier()); + } 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; } /** diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 00fb0651adc4e..866a995585cde 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -91,6 +91,7 @@ import android.security.GateKeeper; import android.service.gatekeeper.IGateKeeperService; import android.service.voice.VoiceInteractionManagerInternal; import android.stats.devicepolicy.DevicePolicyEnums; +import android.telecom.TelecomManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -1760,6 +1761,63 @@ public class UserManagerService extends IUserManager.Stub { } } + /** + * Returns whether switching users is currently allowed for the provided user. + *

+ * Switching users is not allowed in the following cases: + *

  • the user is in a phone call
  • + *
  • {@link UserManager#DISALLOW_USER_SWITCH} is set
  • + *
  • system user hasn't been unlocked yet
  • + * + * @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 (!UserManager.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; + } + @Override public boolean isUserSwitcherEnabled(@UserIdInt int mUserId) { boolean multiUserSettingOn = Settings.Global.getInt(mContext.getContentResolver(),