Loading core/java/android/content/pm/LauncherApps.java +30 −6 Original line number Diff line number Diff line Loading @@ -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>(); Loading Loading @@ -387,6 +388,7 @@ public class LauncherApps { mContext = context; mService = service; mPm = context.getPackageManager(); mUserManager = context.getSystemService(UserManager.class); } /** @hide */ Loading @@ -396,6 +398,16 @@ public class LauncherApps { ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE))); } /** * 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. * Loading @@ -403,14 +415,13 @@ public class LauncherApps { * 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(); } } Loading @@ -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); Loading @@ -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); Loading @@ -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()); } Loading @@ -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); Loading @@ -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), Loading Loading @@ -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( Loading @@ -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) { Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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, Loading Loading @@ -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) { Loading Loading @@ -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()); } Loading services/core/java/com/android/server/pm/LauncherAppsService.java +95 −58 Original line number Diff line number Diff line Loading @@ -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; /** Loading Loading @@ -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); Loading @@ -250,6 +257,7 @@ public class LauncherAppsService extends SystemService { } finally { injectRestoreCallingIdentity(ident); } return true; } @VisibleForTesting // We override it in unit tests Loading Loading @@ -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; } Loading @@ -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; } Loading @@ -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"); Loading @@ -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); } Loading @@ -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; } Loading @@ -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; } Loading @@ -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"); Loading @@ -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( Loading @@ -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 Loading @@ -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; } Loading @@ -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, Loading Loading @@ -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; } Loading @@ -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); } Loading Loading @@ -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); Loading @@ -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()); Loading services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +17 −1 Original line number Diff line number Diff line Loading @@ -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", Loading @@ -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) Loading Loading @@ -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<>( Loading Loading @@ -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); Loading @@ -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(); Loading services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +26 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/content/pm/LauncherApps.java +30 −6 Original line number Diff line number Diff line Loading @@ -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>(); Loading Loading @@ -387,6 +388,7 @@ public class LauncherApps { mContext = context; mService = service; mPm = context.getPackageManager(); mUserManager = context.getSystemService(UserManager.class); } /** @hide */ Loading @@ -396,6 +398,16 @@ public class LauncherApps { ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE))); } /** * 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. * Loading @@ -403,14 +415,13 @@ public class LauncherApps { * 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(); } } Loading @@ -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); Loading @@ -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); Loading @@ -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()); } Loading @@ -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); Loading @@ -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), Loading Loading @@ -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( Loading @@ -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) { Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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, Loading Loading @@ -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) { Loading Loading @@ -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()); } Loading
services/core/java/com/android/server/pm/LauncherAppsService.java +95 −58 Original line number Diff line number Diff line Loading @@ -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; /** Loading Loading @@ -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); Loading @@ -250,6 +257,7 @@ public class LauncherAppsService extends SystemService { } finally { injectRestoreCallingIdentity(ident); } return true; } @VisibleForTesting // We override it in unit tests Loading Loading @@ -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; } Loading @@ -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; } Loading @@ -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"); Loading @@ -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); } Loading @@ -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; } Loading @@ -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; } Loading @@ -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"); Loading @@ -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( Loading @@ -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 Loading @@ -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; } Loading @@ -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, Loading Loading @@ -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; } Loading @@ -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); } Loading Loading @@ -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); Loading @@ -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()); Loading
services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +17 −1 Original line number Diff line number Diff line Loading @@ -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", Loading @@ -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) Loading Loading @@ -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<>( Loading Loading @@ -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); Loading @@ -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(); Loading
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +26 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes