OSDN Git Service

Do not allow work profile to see main other profiles
authorMakoto Onuki <omakoto@google.com>
Thu, 26 Jan 2017 19:39:31 +0000 (11:39 -0800)
committerMakoto Onuki <omakoto@google.com>
Mon, 13 Feb 2017 18:07:46 +0000 (10:07 -0800)
It won't throw SecurityException, but it'll pretend there's
no apps on the other profile.

- Also log an error about it, in the client side process.

- Also still send WTF() about the reverse access.

Bug: 34650921
Bug: 34340531

Test: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest1 -w com.android.frameworks.servicestests
Test: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest2 -w com.android.frameworks.servicestests
Test: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest3 -w com.android.frameworks.servicestests
Test: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest4 -w com.android.frameworks.servicestests
Test: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest5 -w com.android.frameworks.servicestests
Test: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest6 -w com.android.frameworks.servicestests
Test: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest7 -w com.android.frameworks.servicestests
Test: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest8 -w com.android.frameworks.servicestests
Test: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest9 -w com.android.frameworks.servicestests
Test: adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest10 -w com.android.frameworks.servicestests

Test: cts-tradefed run cts --skip-device-info --skip-preconditions --skip-system-status-check com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker -a armeabi-v7a -m CtsShortcutHostTestCases -t 'android.content.pm.cts.shortcuthost.ShortcutManagerMultiuserTest'
Test: cts-tradefed run cts --skip-device-info --skip-preconditions --skip-system-status-check com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker -a armeabi-v7a -m CtsDevicePolicyManagerTestCases -t 'com.android.cts.devicepolicy.LauncherAppsProfileTest'
Change-Id: I6164014685009db3f34a176a3f12c517766b2b49

core/java/android/content/pm/LauncherApps.java
services/core/java/com/android/server/pm/LauncherAppsService.java
services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java

index 999b34f..c8f6406 100644 (file)
@@ -127,9 +127,10 @@ public class LauncherApps {
     public static final String EXTRA_PIN_ITEM_REQUEST =
             "android.content.pm.extra.PIN_ITEM_REQUEST";
 
-    private Context mContext;
-    private ILauncherApps mService;
-    private PackageManager mPm;
+    private final Context mContext;
+    private final ILauncherApps mService;
+    private final PackageManager mPm;
+    private final UserManager mUserManager;
 
     private List<CallbackMessageHandler> mCallbacks
             = new ArrayList<CallbackMessageHandler>();
@@ -387,6 +388,7 @@ public class LauncherApps {
         mContext = context;
         mService = service;
         mPm = context.getPackageManager();
+        mUserManager = context.getSystemService(UserManager.class);
     }
 
     /** @hide */
@@ -397,20 +399,29 @@ public class LauncherApps {
     }
 
     /**
+     * Show an error log on logcat, when the calling user is a managed profile, and the target
+     * user is different from the calling user, in order to help developers to detect it.
+     */
+    private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) {
+        if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()) {
+            Log.e(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
+        }
+    }
+
+    /**
      * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
      *
      * <p>If the caller is running on a managed profile, it'll return only the current profile.
      * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
      */
     public List<UserHandle> getProfiles() {
-        final UserManager um = mContext.getSystemService(UserManager.class);
-        if (um.isManagedProfile()) {
+        if (mUserManager.isManagedProfile()) {
             // If it's a managed profile, only return the current profile.
             final List result =  new ArrayList(1);
             result.add(android.os.Process.myUserHandle());
             return result;
         } else {
-            return um.getUserProfiles();
+            return mUserManager.getUserProfiles();
         }
     }
 
@@ -424,6 +435,7 @@ public class LauncherApps {
      * @return List of launchable activities. Can be an empty list but will not be null.
      */
     public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
+        logErrorForInvalidProfileAccess(user);
         try {
             return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
                     packageName, user), user);
@@ -441,6 +453,7 @@ public class LauncherApps {
      * @return An activity info object if there is a match.
      */
     public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
+        logErrorForInvalidProfileAccess(user);
         try {
             ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(),
                     intent.getComponent(), user);
@@ -464,6 +477,7 @@ public class LauncherApps {
      */
     public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
             Bundle opts) {
+        logErrorForInvalidProfileAccess(user);
         if (DEBUG) {
             Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
         }
@@ -486,6 +500,7 @@ public class LauncherApps {
      */
     public void startAppDetailsActivity(ComponentName component, UserHandle user,
             Rect sourceBounds, Bundle opts) {
+        logErrorForInvalidProfileAccess(user);
         try {
             mService.showAppDetailsAsUser(mContext.getPackageName(),
                     component, sourceBounds, opts, user);
@@ -507,6 +522,7 @@ public class LauncherApps {
      */
     public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
             @NonNull UserHandle user) {
+        logErrorForInvalidProfileAccess(user);
         try {
             return convertToActivityList(mService.getShortcutConfigActivities(
                     mContext.getPackageName(), packageName, user),
@@ -553,6 +569,7 @@ public class LauncherApps {
      * @see Intent#ACTION_CREATE_SHORTCUT
      * @see android.app.Activity#startIntentSenderForResult
      */
+    @Nullable
     public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
         try {
             return mService.getShortcutConfigActivityIntent(
@@ -571,6 +588,7 @@ public class LauncherApps {
      * @return true if the package exists and is enabled.
      */
     public boolean isPackageEnabled(String packageName, UserHandle user) {
+        logErrorForInvalidProfileAccess(user);
         try {
             return mService.isPackageEnabled(mContext.getPackageName(), packageName, user);
         } catch (RemoteException re) {
@@ -591,6 +609,7 @@ public class LauncherApps {
      */
     public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags,
             UserHandle user) {
+        logErrorForInvalidProfileAccess(user);
         try {
             return mService.getApplicationInfo(mContext.getPackageName(), packageName, flags, user);
         } catch (RemoteException re) {
@@ -607,6 +626,7 @@ public class LauncherApps {
      * @return true if the activity exists and is enabled.
      */
     public boolean isActivityEnabled(ComponentName component, UserHandle user) {
+        logErrorForInvalidProfileAccess(user);
         try {
             return mService.isActivityEnabled(mContext.getPackageName(), component, user);
         } catch (RemoteException re) {
@@ -656,6 +676,7 @@ public class LauncherApps {
     @Nullable
     public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
             @NonNull UserHandle user) {
+        logErrorForInvalidProfileAccess(user);
         try {
             return mService.getShortcuts(mContext.getPackageName(),
                     query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
@@ -699,6 +720,7 @@ public class LauncherApps {
      */
     public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
             @NonNull UserHandle user) {
+        logErrorForInvalidProfileAccess(user);
         try {
             mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
         } catch (RemoteException e) {
@@ -866,6 +888,8 @@ public class LauncherApps {
     public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
             @NonNull UserHandle user) {
+        logErrorForInvalidProfileAccess(user);
+
         startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
                 user.getIdentifier());
     }
index b6611eb..179f310 100644 (file)
@@ -64,6 +64,7 @@ import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -216,29 +217,35 @@ public class LauncherAppsService extends SystemService {
             }
         }
 
-        /**
-         * Checks if the caller is in the same group as the userToCheck.
-         */
-        private void ensureInUserProfiles(
-                String callingPackage, UserHandle userToCheck, String message) {
-            ensureInUserProfiles(callingPackage, userToCheck.getIdentifier(), message);
+        /** See {@link #canAccessProfile(String, int, String)} */
+        private boolean canAccessProfile(
+                String callingPackage, UserHandle targetUser, String message) {
+            return canAccessProfile(callingPackage, targetUser.getIdentifier(), message);
         }
 
-        private void ensureInUserProfiles(String callingPackage, int targetUserId, String message) {
+        /**
+         * Checks if the calling user is in the same group as {@code targetUser}, and allowed
+         * to access it.
+         *
+         * @return TRUE if the calling user can access {@code targetUserId}.  FALSE if not *but
+         * they're still in the same profile group*.
+         *
+         * @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;
+            if (targetUserId == callingUserId) return true;
 
             long ident = injectClearCallingIdentity();
             try {
                 UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
                 if (callingUserInfo.isManagedProfile()) {
-                    // TODO: Make it SecurityException.  See b/34650921
-                    // throw new SecurityException(message + " for another profile " + targetUserId);
-
-                    // TODO: Report caller package name.
                     Slog.wtfStack(TAG, message + " by " + callingPackage + " for another profile "
                             + targetUserId + " from " + callingUserId);
+
+                    return false;
                 }
 
                 UserInfo targetUserInfo = mUm.getUserInfo(targetUserId);
@@ -250,6 +257,7 @@ public class LauncherAppsService extends SystemService {
             } finally {
                 injectRestoreCallingIdentity(ident);
             }
+            return true;
         }
 
         @VisibleForTesting // We override it in unit tests
@@ -301,7 +309,9 @@ public class LauncherAppsService extends SystemService {
         public ActivityInfo resolveActivity(
                 String callingPackage, ComponentName component, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(callingPackage, user, "Cannot resolve activity");
+            if (!canAccessProfile(callingPackage, user, "Cannot resolve activity")) {
+                return null;
+            }
             if (!isUserEnabled(user)) {
                 return null;
             }
@@ -328,7 +338,9 @@ public class LauncherAppsService extends SystemService {
 
         private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage,
                 Intent intent, UserHandle user) {
-            ensureInUserProfiles(callingPackage, user, "Cannot retrieve activities");
+            if (!canAccessProfile(callingPackage, user, "Cannot retrieve activities")) {
+                return null;
+            }
             if (!isUserEnabled(user)) {
                 return null;
             }
@@ -348,7 +360,10 @@ public class LauncherAppsService extends SystemService {
         @Override
         public IntentSender getShortcutConfigActivityIntent(String callingPackage,
                 ComponentName component, UserHandle user) throws RemoteException {
-            ensureShortcutPermission(callingPackage, user);
+            ensureShortcutPermission(callingPackage);
+            if (!canAccessProfile(callingPackage, user, "Cannot check package")) {
+                return null;
+            }
             Preconditions.checkNotNull(component);
             Preconditions.checkArgument(isUserEnabled(user), "User not enabled");
 
@@ -356,11 +371,11 @@ public class LauncherAppsService extends SystemService {
             Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component);
             final long identity = Binder.clearCallingIdentity();
             try {
-                return PendingIntent.getActivityAsUser(
+                final PendingIntent pi = PendingIntent.getActivityAsUser(
                         mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
                                 | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
-                        null, user)
-                        .getIntentSender();
+                        null, user);
+                return pi == null ? null : pi.getIntentSender();
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -369,7 +384,9 @@ public class LauncherAppsService extends SystemService {
         @Override
         public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(callingPackage, user, "Cannot check package");
+            if (!canAccessProfile(callingPackage, user, "Cannot check package")) {
+                return false;
+            }
             if (!isUserEnabled(user)) {
                 return false;
             }
@@ -391,7 +408,9 @@ public class LauncherAppsService extends SystemService {
         public ApplicationInfo getApplicationInfo(
                 String callingPackage, String packageName, int flags, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(callingPackage, user, "Cannot check package");
+            if (!canAccessProfile(callingPackage, user, "Cannot check package")) {
+                return null;
+            }
             if (!isUserEnabled(user)) {
                 return null;
             }
@@ -407,14 +426,8 @@ public class LauncherAppsService extends SystemService {
             }
         }
 
-        private void ensureShortcutPermission(@NonNull String callingPackage, UserHandle user) {
-            ensureShortcutPermission(callingPackage, user.getIdentifier());
-        }
-
-        private void ensureShortcutPermission(@NonNull String callingPackage, int userId) {
+        private void ensureShortcutPermission(@NonNull String callingPackage) {
             verifyCallingPackage(callingPackage);
-            ensureInUserProfiles(callingPackage, userId, "Cannot access shortcuts");
-
             if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
                     callingPackage)) {
                 throw new SecurityException("Caller can't access shortcut information");
@@ -424,10 +437,11 @@ public class LauncherAppsService extends SystemService {
         @Override
         public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
                 String packageName, List shortcutIds, ComponentName componentName, int flags,
-                UserHandle user) {
-            ensureShortcutPermission(callingPackage, user);
-            if (!isUserEnabled(user)) {
-                return new ParceledListSlice<>(new ArrayList(0));
+                UserHandle targetUser) {
+            ensureShortcutPermission(callingPackage);
+            if (!canAccessProfile(callingPackage, targetUser, "Cannot get shortcuts")
+                    || !isUserEnabled(targetUser)) {
+                return new ParceledListSlice<>(Collections.EMPTY_LIST);
             }
             if (shortcutIds != null && packageName == null) {
                 throw new IllegalArgumentException(
@@ -438,44 +452,53 @@ public class LauncherAppsService extends SystemService {
             return new ParceledListSlice<>((List<ShortcutInfo>)
                     mShortcutServiceInternal.getShortcuts(getCallingUserId(),
                             callingPackage, changedSince, packageName, shortcutIds,
-                            componentName, flags, user.getIdentifier()));
+                            componentName, flags, targetUser.getIdentifier()));
         }
 
         @Override
         public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
-                UserHandle user) {
-            ensureShortcutPermission(callingPackage, user);
-            if (!isUserEnabled(user)) {
+                UserHandle targetUser) {
+            ensureShortcutPermission(callingPackage);
+            if (!canAccessProfile(callingPackage, targetUser, "Cannot pin shortcuts")) {
+                return;
+            }
+            if (!isUserEnabled(targetUser)) {
                 throw new IllegalStateException("Cannot pin shortcuts for disabled profile "
-                        + user);
+                        + targetUser);
             }
 
             mShortcutServiceInternal.pinShortcuts(getCallingUserId(),
-                    callingPackage, packageName, ids, user.getIdentifier());
+                    callingPackage, packageName, ids, targetUser.getIdentifier());
         }
 
         @Override
         public int getShortcutIconResId(String callingPackage, String packageName, String id,
-                int userId) {
-            ensureShortcutPermission(callingPackage, userId);
-            if (!isUserEnabled(userId)) {
+                int targetUserId) {
+            ensureShortcutPermission(callingPackage);
+            if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) {
+                return 0;
+            }
+            if (!isUserEnabled(targetUserId)) {
                 return 0;
             }
 
             return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(),
-                    callingPackage, packageName, id, userId);
+                    callingPackage, packageName, id, targetUserId);
         }
 
         @Override
         public ParcelFileDescriptor getShortcutIconFd(String callingPackage,
-                String packageName, String id, int userId) {
-            ensureShortcutPermission(callingPackage, userId);
-            if (!isUserEnabled(userId)) {
+                String packageName, String id, int targetUserId) {
+            ensureShortcutPermission(callingPackage);
+            if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) {
+                return null;
+            }
+            if (!isUserEnabled(targetUserId)) {
                 return null;
             }
 
             return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(),
-                    callingPackage, packageName, id, userId);
+                    callingPackage, packageName, id, targetUserId);
         }
 
         @Override
@@ -487,23 +510,27 @@ public class LauncherAppsService extends SystemService {
 
         @Override
         public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
-                Rect sourceBounds, Bundle startActivityOptions, int userId) {
+                Rect sourceBounds, Bundle startActivityOptions, int targetUserId) {
             verifyCallingPackage(callingPackage);
-            ensureInUserProfiles(callingPackage, userId, "Cannot start activity");
-
-            if (!isUserEnabled(userId)) {
+            if (!canAccessProfile(callingPackage, targetUserId, "Cannot start activity")) {
+                return false;
+            }
+            if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) {
+                return false;
+            }
+            if (!isUserEnabled(targetUserId)) {
                 throw new IllegalStateException("Cannot start a shortcut for disabled profile "
-                        + userId);
+                        + targetUserId);
             }
 
             // Even without the permission, pinned shortcuts are always launchable.
             if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(),
-                    callingPackage, packageName, shortcutId, userId)) {
-                ensureShortcutPermission(callingPackage, userId);
+                    callingPackage, packageName, shortcutId, targetUserId)) {
+                ensureShortcutPermission(callingPackage);
             }
 
             final Intent[] intents = mShortcutServiceInternal.createShortcutIntents(
-                    getCallingUserId(), callingPackage, packageName, shortcutId, userId);
+                    getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId);
             if (intents == null || intents.length == 0) {
                 return false;
             }
@@ -513,7 +540,7 @@ public class LauncherAppsService extends SystemService {
             intents[0].setSourceBounds(sourceBounds);
 
             return startShortcutIntentsAsPublisher(
-                    intents, packageName, startActivityOptions, userId);
+                    intents, packageName, startActivityOptions, targetUserId);
         }
 
         private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents,
@@ -543,7 +570,9 @@ public class LauncherAppsService extends SystemService {
         public boolean isActivityEnabled(
                 String callingPackage, ComponentName component, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(callingPackage , user, "Cannot check component");
+            if (!canAccessProfile(callingPackage , user, "Cannot check component")) {
+                return false;
+            }
             if (!isUserEnabled(user)) {
                 return false;
             }
@@ -565,7 +594,9 @@ public class LauncherAppsService extends SystemService {
         public void startActivityAsUser(String callingPackage,
                 ComponentName component, Rect sourceBounds,
                 Bundle opts, UserHandle user) throws RemoteException {
-            ensureInUserProfiles(callingPackage, user, "Cannot start activity");
+            if (!canAccessProfile(callingPackage, user, "Cannot start activity")) {
+                return;
+            }
             if (!isUserEnabled(user)) {
                 throw new IllegalStateException("Cannot start activity for disabled profile "  + user);
             }
@@ -618,7 +649,9 @@ public class LauncherAppsService extends SystemService {
         @Override
         public void showAppDetailsAsUser(String callingPackage, ComponentName component,
                 Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException {
-            ensureInUserProfiles(callingPackage, user, "Cannot show app details");
+            if (!canAccessProfile(callingPackage, user, "Cannot show app details")) {
+                return;
+            }
             if (!isUserEnabled(user)) {
                 throw new IllegalStateException("Cannot show app details for disabled profile "
                         + user);
@@ -642,9 +675,13 @@ public class LauncherAppsService extends SystemService {
         private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
                 String debugMsg) {
             if (user.getIdentifier() == listeningUser.getIdentifier()) {
-                if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg);
+                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());
index 8c23a91..e2e1844 100644 (file)
@@ -602,12 +602,14 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
     protected static final int USER_0 = UserHandle.USER_SYSTEM;
     protected static final int USER_10 = 10;
     protected static final int USER_11 = 11;
-    protected static final int USER_P0 = 20; // profile of user 0
+    protected static final int USER_P0 = 20; // profile of user 0 (MANAGED_PROFILE *not* set)
+    protected static final int USER_P1 = 21; // another profile of user 0 (MANAGED_PROFILE set)
 
     protected static final UserHandle HANDLE_USER_0 = UserHandle.of(USER_0);
     protected static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10);
     protected static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11);
     protected static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0);
+    protected static final UserHandle HANDLE_USER_P1 = UserHandle.of(USER_P1);
 
     protected static final UserInfo USER_INFO_0 = withProfileGroupId(
             new UserInfo(USER_0, "user0",
@@ -630,6 +632,10 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
     protected static final UserInfo USER_INFO_P0 = withProfileGroupId(
             new UserInfo(USER_P0, "userP0", UserInfo.FLAG_INITIALIZED), 0);
 
+    protected static final UserInfo USER_INFO_P1 = withProfileGroupId(
+            new UserInfo(USER_P1, "userP1",
+                    UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE), 0);
+
     protected BiPredicate<String, Integer> mDefaultLauncherChecker =
             (callingPackage, userId) ->
             LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
@@ -746,6 +752,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
         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<>(
@@ -775,6 +782,13 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
                     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();
+                }));
 
         when(mMockActivityManagerInternal.getUidProcessState(anyInt())).thenReturn(
                 ActivityManager.PROCESS_STATE_CACHED_EMPTY);
@@ -784,12 +798,14 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
         mRunningUsers.put(USER_10, false);
         mRunningUsers.put(USER_11, false);
         mRunningUsers.put(USER_P0, true);
+        mRunningUsers.put(USER_P1, true);
 
         // Unlock all users by default.
         mUnlockedUsers.put(USER_0, true);
         mUnlockedUsers.put(USER_10, true);
         mUnlockedUsers.put(USER_11, true);
         mUnlockedUsers.put(USER_P0, true);
+        mUnlockedUsers.put(USER_P1, true);
 
         // Set up resources
         setUpAppResources();
index 74c1ca5..980aa2d 100644 (file)
@@ -2099,6 +2099,24 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
                     list("s1", "s2", "s3"), HANDLE_USER_10);
         });
 
+        // First, make sure managed profile can't see other profiles.
+        runWithCaller(LAUNCHER_1, USER_P1, () -> {
+
+            final ShortcutQuery q = new ShortcutQuery().setQueryFlags(
+                    ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_PINNED
+                    | ShortcutQuery.FLAG_MATCH_MANIFEST);
+
+            // No shortcuts are visible.
+            assertWith(mLauncherApps.getShortcuts(q, HANDLE_USER_0)).isEmpty();
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
+
+            // Should have no effects.
+            assertWith(mLauncherApps.getShortcuts(q, HANDLE_USER_0)).isEmpty();
+
+            assertShortcutNotLaunched(CALLING_PACKAGE_1, "s1", USER_0);
+        });
+
         // Cross profile pinning.
         final int PIN_AND_DYNAMIC = ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC;
 
@@ -2930,6 +2948,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         final LauncherApps.Callback c0_4 = mock(LauncherApps.Callback.class);
 
         final LauncherApps.Callback cP0_1 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback cP1_1 = mock(LauncherApps.Callback.class);
         final LauncherApps.Callback c10_1 = mock(LauncherApps.Callback.class);
         final LauncherApps.Callback c10_2 = mock(LauncherApps.Callback.class);
         final LauncherApps.Callback c11_1 = mock(LauncherApps.Callback.class);
@@ -2943,6 +2962,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
                     return LAUNCHER_2.equals(pkg);
                 case USER_P0:
                     return LAUNCHER_1.equals(pkg);
+                case USER_P1:
+                    return LAUNCHER_1.equals(pkg);
                 case USER_10:
                     return LAUNCHER_1.equals(pkg);
                 case USER_11:
@@ -2957,6 +2978,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         runWithCaller(LAUNCHER_3, USER_0, () -> mLauncherApps.registerCallback(c0_3, h));
         runWithCaller(LAUNCHER_4, USER_0, () -> mLauncherApps.registerCallback(c0_4, h));
         runWithCaller(LAUNCHER_1, USER_P0, () -> mLauncherApps.registerCallback(cP0_1, h));
+        runWithCaller(LAUNCHER_1, USER_P1, () -> mLauncherApps.registerCallback(cP1_1, h));
         runWithCaller(LAUNCHER_1, USER_10, () -> mLauncherApps.registerCallback(c10_1, h));
         runWithCaller(LAUNCHER_2, USER_10, () -> mLauncherApps.registerCallback(c10_2, h));
         runWithCaller(LAUNCHER_1, USER_11, () -> mLauncherApps.registerCallback(c11_1, h));
@@ -2977,6 +2999,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         assertCallbackNotReceived(c11_1);
         assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3");
         assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+        assertCallbackNotReceived(cP1_1);
 
         // User 0, different package.
 
@@ -2995,6 +3018,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_3, "s1", "s2", "s3", "s4");
         assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_3,
                 "s1", "s2", "s3", "s4", "s5", "s6");
+        assertCallbackNotReceived(cP1_1);
 
         // Work profile.
         resetAll(all);
@@ -3011,6 +3035,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         assertCallbackNotReceived(c11_1);
         assertCallbackReceived(c0_2, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s5");
         assertCallbackReceived(cP0_1, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+        assertCallbackNotReceived(cP1_1);
 
         // Normal secondary user.
         mRunningUsers.put(USER_10, true);
@@ -3030,6 +3055,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
         assertCallbackNotReceived(c11_1);
         assertCallbackReceived(c10_1, HANDLE_USER_10, CALLING_PACKAGE_1,
                 "x1", "x2", "x3", "x4", "x5");
+        assertCallbackNotReceived(cP1_1);
     }
 
     // === Test for persisting ===