diff options
5 files changed, 147 insertions, 216 deletions
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java index 6c9f1b25bf66..f09d5cee4e61 100644 --- a/core/java/android/os/UserManagerInternal.java +++ b/core/java/android/os/UserManagerInternal.java @@ -186,4 +186,24 @@ public abstract class UserManagerInternal { * @return the array of user ids. */ public abstract int[] getUserIds(); + + /** + * Checks if the {@code callingUserId} and {@code targetUserId} are same or in same group + * and that the {@code callingUserId} is not a managed profile and + * {@code targetUserId} is enabled. + * + * @return TRUE if the {@code callingUserId} can access {@code targetUserId}. FALSE + * otherwise + * + * @throws SecurityException if the calling user and {@code targetUser} are not in the same + * group and {@code throwSecurityException} is true, otherwise if will simply return false. + */ + public abstract boolean isProfileAccessible(int callingUserId, int targetUserId, + String debugMsg, boolean throwSecurityException); + + /** + * If {@code userId} is of a managed profile, return the parent user ID. Otherwise return + * itself. + */ + public abstract int getProfileParentId(int userId); } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 14995b3827e1..fb3839805b1a 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -39,7 +39,6 @@ import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutServiceInternal; import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener; -import android.content.pm.UserInfo; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; @@ -50,7 +49,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; -import android.os.UserManager; +import android.os.UserManagerInternal; import android.provider.Settings; import android.util.Log; import android.util.Slog; @@ -102,7 +101,7 @@ public class LauncherAppsService extends SystemService { private static final boolean DEBUG = false; private static final String TAG = "LauncherAppsService"; private final Context mContext; - private final UserManager mUm; + private final UserManagerInternal mUserManagerInternal; private final ActivityManagerInternal mActivityManagerInternal; private final ShortcutServiceInternal mShortcutServiceInternal; private final PackageCallbackList<IOnAppsChangedListener> mListeners @@ -114,7 +113,8 @@ public class LauncherAppsService extends SystemService { public LauncherAppsImpl(Context context) { mContext = context; - mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + mUserManagerInternal = Preconditions.checkNotNull( + LocalServices.getService(UserManagerInternal.class)); mActivityManagerInternal = Preconditions.checkNotNull( LocalServices.getService(ActivityManagerInternal.class)); mShortcutServiceInternal = Preconditions.checkNotNull( @@ -222,12 +222,6 @@ public class LauncherAppsService extends SystemService { } } - /** See {@link #canAccessProfile(String, int, String)} */ - private boolean canAccessProfile( - String callingPackage, UserHandle targetUser, String message) { - return canAccessProfile(callingPackage, targetUser.getIdentifier(), message); - } - /** * Checks if the calling user is in the same group as {@code targetUser}, and allowed * to access it. @@ -238,30 +232,9 @@ public class LauncherAppsService extends SystemService { * @throws SecurityException if the calling user and {@code targetUser} are not in the same * group. */ - private boolean canAccessProfile(String callingPackage, int targetUserId, String message) { - final int callingUserId = injectCallingUserId(); - - if (targetUserId == callingUserId) return true; - - long ident = injectClearCallingIdentity(); - try { - UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); - if (callingUserInfo.isManagedProfile()) { - Slog.w(TAG, message + " by " + callingPackage + " for another profile " - + targetUserId + " from " + callingUserId); - return false; - } - - UserInfo targetUserInfo = mUm.getUserInfo(targetUserId); - if (targetUserInfo == null - || targetUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID - || targetUserInfo.profileGroupId != callingUserInfo.profileGroupId) { - throw new SecurityException(message + " for unrelated profile " + targetUserId); - } - } finally { - injectRestoreCallingIdentity(ident); - } - return true; + private boolean canAccessProfile(int targetUserId, String message) { + return mUserManagerInternal.isProfileAccessible(injectCallingUserId(), targetUserId, + message, true); } @VisibleForTesting // We override it in unit tests @@ -283,23 +256,6 @@ public class LauncherAppsService extends SystemService { } } - /** - * Checks if the user is enabled. - */ - private boolean isUserEnabled(UserHandle user) { - return isUserEnabled(user.getIdentifier()); - } - - private boolean isUserEnabled(int userId) { - long ident = injectClearCallingIdentity(); - try { - UserInfo targetUserInfo = mUm.getUserInfo(userId); - return targetUserInfo != null && targetUserInfo.isEnabled(); - } finally { - injectRestoreCallingIdentity(ident); - } - } - @Override public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage, String packageName, UserHandle user) @@ -315,10 +271,7 @@ public class LauncherAppsService extends SystemService { public ActivityInfo resolveActivity( String callingPackage, ComponentName component, UserHandle user) throws RemoteException { - if (!canAccessProfile(callingPackage, user, "Cannot resolve activity")) { - return null; - } - if (!isUserEnabled(user)) { + if (!canAccessProfile(user.getIdentifier(), "Cannot resolve activity")) { return null; } @@ -346,10 +299,7 @@ public class LauncherAppsService extends SystemService { private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage, Intent intent, UserHandle user) { - if (!canAccessProfile(callingPackage, user, "Cannot retrieve activities")) { - return null; - } - if (!isUserEnabled(user)) { + if (!canAccessProfile(user.getIdentifier(), "Cannot retrieve activities")) { return null; } @@ -372,11 +322,10 @@ public class LauncherAppsService extends SystemService { public IntentSender getShortcutConfigActivityIntent(String callingPackage, ComponentName component, UserHandle user) throws RemoteException { ensureShortcutPermission(callingPackage); - if (!canAccessProfile(callingPackage, user, "Cannot check package")) { + if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { return null; } Preconditions.checkNotNull(component); - Preconditions.checkArgument(isUserEnabled(user), "User not enabled"); // All right, create the sender. Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component); @@ -395,10 +344,7 @@ public class LauncherAppsService extends SystemService { @Override public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user) throws RemoteException { - if (!canAccessProfile(callingPackage, user, "Cannot check package")) { - return false; - } - if (!isUserEnabled(user)) { + if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { return false; } @@ -421,10 +367,7 @@ public class LauncherAppsService extends SystemService { public ApplicationInfo getApplicationInfo( String callingPackage, String packageName, int flags, UserHandle user) throws RemoteException { - if (!canAccessProfile(callingPackage, user, "Cannot check package")) { - return null; - } - if (!isUserEnabled(user)) { + if (!canAccessProfile(user.getIdentifier(), "Cannot check package")) { return null; } @@ -454,8 +397,7 @@ public class LauncherAppsService extends SystemService { String packageName, List shortcutIds, ComponentName componentName, int flags, UserHandle targetUser) { ensureShortcutPermission(callingPackage); - if (!canAccessProfile(callingPackage, targetUser, "Cannot get shortcuts") - || !isUserEnabled(targetUser)) { + if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) { return new ParceledListSlice<>(Collections.EMPTY_LIST); } if (shortcutIds != null && packageName == null) { @@ -475,13 +417,9 @@ public class LauncherAppsService extends SystemService { public void pinShortcuts(String callingPackage, String packageName, List<String> ids, UserHandle targetUser) { ensureShortcutPermission(callingPackage); - if (!canAccessProfile(callingPackage, targetUser, "Cannot pin shortcuts")) { + if (!canAccessProfile(targetUser.getIdentifier(), "Cannot pin shortcuts")) { return; } - if (!isUserEnabled(targetUser)) { - throw new IllegalStateException("Cannot pin shortcuts for disabled profile " - + targetUser); - } mShortcutServiceInternal.pinShortcuts(getCallingUserId(), callingPackage, packageName, ids, targetUser.getIdentifier()); @@ -491,10 +429,7 @@ public class LauncherAppsService extends SystemService { public int getShortcutIconResId(String callingPackage, String packageName, String id, int targetUserId) { ensureShortcutPermission(callingPackage); - if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) { - return 0; - } - if (!isUserEnabled(targetUserId)) { + if (!canAccessProfile(targetUserId, "Cannot access shortcuts")) { return 0; } @@ -506,10 +441,7 @@ public class LauncherAppsService extends SystemService { public ParcelFileDescriptor getShortcutIconFd(String callingPackage, String packageName, String id, int targetUserId) { ensureShortcutPermission(callingPackage); - if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) { - return null; - } - if (!isUserEnabled(targetUserId)) { + if (!canAccessProfile(targetUserId, "Cannot access shortcuts")) { return null; } @@ -528,13 +460,9 @@ public class LauncherAppsService extends SystemService { public boolean startShortcut(String callingPackage, String packageName, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, int targetUserId) { verifyCallingPackage(callingPackage); - if (!canAccessProfile(callingPackage, targetUserId, "Cannot start activity")) { + if (!canAccessProfile(targetUserId, "Cannot start activity")) { return false; } - if (!isUserEnabled(targetUserId)) { - throw new IllegalStateException("Cannot start a shortcut for disabled profile " - + targetUserId); - } // Even without the permission, pinned shortcuts are always launchable. if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(), @@ -581,10 +509,7 @@ public class LauncherAppsService extends SystemService { public boolean isActivityEnabled( String callingPackage, ComponentName component, UserHandle user) throws RemoteException { - if (!canAccessProfile(callingPackage , user, "Cannot check component")) { - return false; - } - if (!isUserEnabled(user)) { + if (!canAccessProfile(user.getIdentifier(), "Cannot check component")) { return false; } @@ -607,12 +532,9 @@ public class LauncherAppsService extends SystemService { public void startActivityAsUser(String callingPackage, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { - if (!canAccessProfile(callingPackage, user, "Cannot start activity")) { + if (!canAccessProfile(user.getIdentifier(), "Cannot start activity")) { return; } - if (!isUserEnabled(user)) { - throw new IllegalStateException("Cannot start activity for disabled profile " + user); - } Intent launchIntent = new Intent(Intent.ACTION_MAIN); launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); @@ -665,13 +587,9 @@ public class LauncherAppsService extends SystemService { @Override public void showAppDetailsAsUser(String callingPackage, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { - if (!canAccessProfile(callingPackage, user, "Cannot show app details")) { + if (!canAccessProfile(user.getIdentifier(), "Cannot show app details")) { return; } - if (!isUserEnabled(user)) { - throw new IllegalStateException("Cannot show app details for disabled profile " - + user); - } long ident = Binder.clearCallingIdentity(); try { @@ -688,39 +606,10 @@ public class LauncherAppsService extends SystemService { /** Checks if user is a profile of or same as listeningUser. * and the user is enabled. */ - private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, + private boolean isEnabledProfileOf(UserHandle listeningUser, UserHandle user, String debugMsg) { - if (user.getIdentifier() == listeningUser.getIdentifier()) { - if (DEBUG) Log.d(TAG, "Delivering msg to same user: " + debugMsg); - return true; - } - if (mUm.isManagedProfile(listeningUser.getIdentifier())) { - if (DEBUG) Log.d(TAG, "Managed profile can't see other profiles: " + debugMsg); - return false; - } - long ident = injectClearCallingIdentity(); - try { - UserInfo userInfo = mUm.getUserInfo(user.getIdentifier()); - UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier()); - if (userInfo == null || listeningUserInfo == null - || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID - || userInfo.profileGroupId != listeningUserInfo.profileGroupId - || !userInfo.isEnabled()) { - if (DEBUG) { - Log.d(TAG, "Not delivering msg from " + user + " to " + listeningUser + ":" - + debugMsg); - } - return false; - } else { - if (DEBUG) { - Log.d(TAG, "Delivering msg from " + user + " to " + listeningUser + ":" - + debugMsg); - } - return true; - } - } finally { - injectRestoreCallingIdentity(ident); - } + return mUserManagerInternal.isProfileAccessible(listeningUser.getIdentifier(), + user.getIdentifier(), debugMsg, false); } @VisibleForTesting @@ -740,7 +629,7 @@ public class LauncherAppsService extends SystemService { for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); - if (!isEnabledProfileOf(user, cookie.user, "onPackageAdded")) continue; + if (!isEnabledProfileOf(cookie.user, user, "onPackageAdded")) continue; try { listener.onPackageAdded(user, packageName); } catch (RemoteException re) { @@ -762,7 +651,7 @@ public class LauncherAppsService extends SystemService { for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); - if (!isEnabledProfileOf(user, cookie.user, "onPackageRemoved")) continue; + if (!isEnabledProfileOf(cookie.user, user, "onPackageRemoved")) continue; try { listener.onPackageRemoved(user, packageName); } catch (RemoteException re) { @@ -784,7 +673,7 @@ public class LauncherAppsService extends SystemService { for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); - if (!isEnabledProfileOf(user, cookie.user, "onPackageModified")) continue; + if (!isEnabledProfileOf(cookie.user, user, "onPackageModified")) continue; try { listener.onPackageChanged(user, packageName); } catch (RemoteException re) { @@ -806,7 +695,7 @@ public class LauncherAppsService extends SystemService { for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); - if (!isEnabledProfileOf(user, cookie.user, "onPackagesAvailable")) continue; + if (!isEnabledProfileOf(cookie.user, user, "onPackagesAvailable")) continue; try { listener.onPackagesAvailable(user, packages, isReplacing()); } catch (RemoteException re) { @@ -828,7 +717,7 @@ public class LauncherAppsService extends SystemService { for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); - if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnavailable")) continue; + if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnavailable")) continue; try { listener.onPackagesUnavailable(user, packages, isReplacing()); } catch (RemoteException re) { @@ -850,7 +739,7 @@ public class LauncherAppsService extends SystemService { for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); - if (!isEnabledProfileOf(user, cookie.user, "onPackagesSuspended")) continue; + if (!isEnabledProfileOf(cookie.user, user, "onPackagesSuspended")) continue; try { listener.onPackagesSuspended(user, packages); } catch (RemoteException re) { @@ -872,7 +761,7 @@ public class LauncherAppsService extends SystemService { for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); - if (!isEnabledProfileOf(user, cookie.user, "onPackagesUnsuspended")) continue; + if (!isEnabledProfileOf(cookie.user, user, "onPackagesUnsuspended")) continue; try { listener.onPackagesUnsuspended(user, packages); } catch (RemoteException re) { @@ -901,7 +790,7 @@ public class LauncherAppsService extends SystemService { for (int i = 0; i < n; i++) { IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i); - if (!isEnabledProfileOf(user, cookie.user, "onShortcutChanged")) continue; + if (!isEnabledProfileOf(cookie.user, user, "onShortcutChanged")) continue; final int launcherUserId = cookie.user.getIdentifier(); diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 8c3518831b7b..265cc8ebe4d3 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -77,7 +77,7 @@ import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; import android.os.UserHandle; -import android.os.UserManager; +import android.os.UserManagerInternal; import android.text.TextUtils; import android.text.format.Time; import android.util.ArraySet; @@ -315,7 +315,7 @@ public class ShortcutService extends IShortcutService.Stub { private final IPackageManager mIPackageManager; private final PackageManagerInternal mPackageManagerInternal; - private final UserManager mUserManager; + private final UserManagerInternal mUserManagerInternal; private final UsageStatsManagerInternal mUsageStatsManagerInternal; private final ActivityManagerInternal mActivityManagerInternal; @@ -430,7 +430,8 @@ public class ShortcutService extends IShortcutService.Stub { mIPackageManager = AppGlobals.getPackageManager(); mPackageManagerInternal = Preconditions.checkNotNull( LocalServices.getService(PackageManagerInternal.class)); - mUserManager = Preconditions.checkNotNull(context.getSystemService(UserManager.class)); + mUserManagerInternal = Preconditions.checkNotNull( + LocalServices.getService(UserManagerInternal.class)); mUsageStatsManagerInternal = Preconditions.checkNotNull( LocalServices.getService(UsageStatsManagerInternal.class)); mActivityManagerInternal = Preconditions.checkNotNull( @@ -1176,12 +1177,7 @@ public class ShortcutService extends IShortcutService.Stub { // the user might just have been unlocked. // Note we just don't use isUserUnlockingOrUnlocked() here, because it'll return false // when the user is STOPPING, which we still want to consider as "unlocked". - final long token = injectClearCallingIdentity(); - try { - return mUserManager.isUserUnlockingOrUnlocked(userId); - } finally { - injectRestoreCallingIdentity(token); - } + return mUserManagerInternal.isUserUnlockingOrUnlocked(userId); } // Requires mLock held, but "Locked" prefix would look weired so we jsut say "L". @@ -3493,13 +3489,7 @@ public class ShortcutService extends IShortcutService.Stub { * itself. */ int getParentOrSelfUserId(int userId) { - final long token = injectClearCallingIdentity(); - try { - final UserInfo parent = mUserManager.getProfileParent(userId); - return (parent != null) ? parent.id : userId; - } finally { - injectRestoreCallingIdentity(token); - } + return mUserManagerInternal.getProfileParentId(userId); } void injectSendIntentSender(IntentSender intentSender, Intent extras) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 2c7df6c31bed..ced2a7e48e44 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -781,14 +781,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public int getProfileParentId(int userHandle) { checkManageUsersPermission("get the profile parent"); - synchronized (mUsersLock) { - UserInfo profileParent = getProfileParentLU(userHandle); - if (profileParent == null) { - return userHandle; - } - - return profileParent.id; - } + return mLocalService.getProfileParentId(userHandle); } private UserInfo getProfileParentLU(int userHandle) { @@ -3928,6 +3921,56 @@ public class UserManagerService extends IUserManager.Stub { public boolean exists(int userId) { return getUserInfoNoChecks(userId) != null; } + + @Override + public boolean isProfileAccessible(int callingUserId, int targetUserId, String debugMsg, + boolean throwSecurityException) { + if (targetUserId == callingUserId) { + return true; + } + synchronized (mUsersLock) { + UserInfo callingUserInfo = getUserInfoLU(callingUserId); + if (callingUserInfo == null || callingUserInfo.isManagedProfile()) { + if (throwSecurityException) { + throw new SecurityException( + debugMsg + " for another profile " + + targetUserId + " from " + callingUserId); + } + } + + UserInfo targetUserInfo = getUserInfoLU(targetUserId); + if (targetUserInfo == null || !targetUserInfo.isEnabled()) { + // Do not throw any exception here as this could happen due to race conditions + // between the system updating its state and the client getting notified. + if (throwSecurityException) { + Slog.w(LOG_TAG, debugMsg + " for disabled profile " + + targetUserId + " from " + callingUserId); + } + return false; + } + + if (targetUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID || + targetUserInfo.profileGroupId != callingUserInfo.profileGroupId) { + if (throwSecurityException) { + throw new SecurityException( + debugMsg + " for unrelated profile " + targetUserId); + } + return false; + } + } + return true; + } + + @Override + public int getProfileParentId(int userId) { + synchronized (mUsersLock) { + UserInfo profileParent = getProfileParentLU(userId); + if (profileParent == null) { + return userId; + } + return profileParent.id; + } + } } /* Remove all the users except of the system one. */ diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 4ca1647ef415..51d27fe016f0 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -23,6 +23,7 @@ import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; @@ -76,6 +77,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.test.InstrumentationTestCase; import android.test.mock.MockContext; import android.util.ArrayMap; @@ -90,8 +92,6 @@ import com.android.server.pm.ShortcutUser.PackageWithUser; import org.junit.Assert; import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; @@ -111,7 +111,6 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.Consumer; -import java.util.function.Function; public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected static final String TAG = "ShortcutManagerTest"; @@ -604,6 +603,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected PackageManager mMockPackageManager; protected PackageManagerInternal mMockPackageManagerInternal; protected UserManager mMockUserManager; + protected UserManagerInternal mMockUserManagerInternal; protected UsageStatsManagerInternal mMockUsageStatsManagerInternal; protected ActivityManagerInternal mMockActivityManagerInternal; @@ -742,6 +742,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { mMockPackageManager = mock(PackageManager.class); mMockPackageManagerInternal = mock(PackageManagerInternal.class); mMockUserManager = mock(UserManager.class); + mMockUserManagerInternal = mock(UserManagerInternal.class); mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class); mMockActivityManagerInternal = mock(ActivityManagerInternal.class); @@ -751,6 +752,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { LocalServices.addService(UsageStatsManagerInternal.class, mMockUsageStatsManagerInternal); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, mMockActivityManagerInternal); + LocalServices.removeServiceForTest(UserManagerInternal.class); + LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal); // Prepare injection values. @@ -782,50 +785,54 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { deleteAllSavedFiles(); // Set up users. - when(mMockUserManager.getUserInfo(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( - inv -> mUserInfos.get((Integer) inv.getArguments()[0]))); - mUserInfos.put(USER_0, USER_INFO_0); mUserInfos.put(USER_10, USER_INFO_10); mUserInfos.put(USER_11, USER_INFO_11); mUserInfos.put(USER_P0, USER_INFO_P0); mUserInfos.put(USER_P1, USER_INFO_P1); - // Set up isUserRunning and isUserUnlocked. - when(mMockUserManager.isUserRunning(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( - inv -> b(mRunningUsers.get((Integer) inv.getArguments()[0])))); - - when(mMockUserManager.isUserUnlocked(anyInt())) - .thenAnswer(new AnswerWithSystemCheck<>(inv -> { - final int userId = (Integer) inv.getArguments()[0]; - return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId)); - })); - // isUserUnlockingOrUnlocked() return the same value as isUserUnlocked(). - when(mMockUserManager.isUserUnlockingOrUnlocked(anyInt())) - .thenAnswer(new AnswerWithSystemCheck<>(inv -> { + when(mMockUserManagerInternal.isUserUnlockingOrUnlocked(anyInt())) + .thenAnswer(inv -> { final int userId = (Integer) inv.getArguments()[0]; return b(mRunningUsers.get(userId)) && b(mUnlockedUsers.get(userId)); - })); - - when(mMockUserManager.getProfileParent(anyInt())) - .thenAnswer(new AnswerWithSystemCheck<>(inv -> { + }); + when(mMockUserManagerInternal.getProfileParentId(anyInt())) + .thenAnswer(inv -> { final int userId = (Integer) inv.getArguments()[0]; final UserInfo ui = mUserInfos.get(userId); assertNotNull(ui); if (ui.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) { - return null; + return userId; } final UserInfo parent = mUserInfos.get(ui.profileGroupId); assertNotNull(parent); - return parent; - })); - when(mMockUserManager.isManagedProfile(anyInt())) - .thenAnswer(new AnswerWithSystemCheck<>(inv -> { - final int userId = (Integer) inv.getArguments()[0]; - final UserInfo ui = mUserInfos.get(userId); - assertNotNull(ui); - return ui.isManagedProfile(); - })); + return parent.id; + }); + + when(mMockUserManagerInternal.isProfileAccessible(anyInt(), anyInt(), anyString(), + anyBoolean())).thenAnswer(inv -> { + final int callingUserId = (Integer) inv.getArguments()[0]; + final int targetUserId = (Integer) inv.getArguments()[1]; + if (targetUserId == callingUserId) { + return true; + } + final UserInfo callingUserInfo = mUserInfos.get(callingUserId); + final UserInfo targetUserInfo = mUserInfos.get(targetUserId); + if (callingUserInfo == null || callingUserInfo.isManagedProfile() + || targetUserInfo == null || !targetUserInfo.isEnabled()) { + return false; + } + if (targetUserInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID + && targetUserInfo.profileGroupId == callingUserInfo.profileGroupId) { + return true; + } + final boolean isExternal = (Boolean) inv.getArguments()[3]; + if (!isExternal) { + return false; + } + throw new SecurityException(inv.getArguments()[2] + " for unrelated profile " + + targetUserId); + }); when(mMockActivityManagerInternal.getUidProcessState(anyInt())).thenReturn( ActivityManager.PROCESS_STATE_CACHED_EMPTY); @@ -860,24 +867,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { return (value != null && value); } - /** - * Returns a boolean but also checks if the current UID is SYSTEM_UID. - */ - protected class AnswerWithSystemCheck<T> implements Answer<T> { - private final Function<InvocationOnMock, T> mChecker; - - public AnswerWithSystemCheck(Function<InvocationOnMock, T> checker) { - mChecker = checker; - } - - @Override - public T answer(InvocationOnMock invocation) throws Throwable { - assertEquals("Must be called on SYSTEM UID.", - Process.SYSTEM_UID, mInjectedCallingUid); - return mChecker.apply(invocation); - } - } - protected void setUpAppResources() throws Exception { setUpAppResources(/* offset = */ 0); } |