Loading core/java/android/content/pm/LauncherApps.java +30 −6 Original line number Original line Diff line number Diff line Loading @@ -127,9 +127,10 @@ public class LauncherApps { public static final String EXTRA_PIN_ITEM_REQUEST = public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST"; "android.content.pm.extra.PIN_ITEM_REQUEST"; private Context mContext; private final Context mContext; private ILauncherApps mService; private final ILauncherApps mService; private PackageManager mPm; private final PackageManager mPm; private final UserManager mUserManager; private List<CallbackMessageHandler> mCallbacks private List<CallbackMessageHandler> mCallbacks = new ArrayList<CallbackMessageHandler>(); = new ArrayList<CallbackMessageHandler>(); Loading Loading @@ -387,6 +388,7 @@ public class LauncherApps { mContext = context; mContext = context; mService = service; mService = service; mPm = context.getPackageManager(); mPm = context.getPackageManager(); mUserManager = context.getSystemService(UserManager.class); } } /** @hide */ /** @hide */ Loading @@ -396,6 +398,16 @@ public class LauncherApps { ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE))); 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. * 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. * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would. */ */ public List<UserHandle> getProfiles() { public List<UserHandle> getProfiles() { final UserManager um = mContext.getSystemService(UserManager.class); if (mUserManager.isManagedProfile()) { if (um.isManagedProfile()) { // If it's a managed profile, only return the current profile. // If it's a managed profile, only return the current profile. final List result = new ArrayList(1); final List result = new ArrayList(1); result.add(android.os.Process.myUserHandle()); result.add(android.os.Process.myUserHandle()); return result; return result; } else { } 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. * @return List of launchable activities. Can be an empty list but will not be null. */ */ public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) { public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(), return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(), packageName, user), user); packageName, user), user); Loading @@ -441,6 +453,7 @@ public class LauncherApps { * @return An activity info object if there is a match. * @return An activity info object if there is a match. */ */ public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) { public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(), ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(), intent.getComponent(), user); intent.getComponent(), user); Loading @@ -464,6 +477,7 @@ public class LauncherApps { */ */ public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds, public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds, Bundle opts) { Bundle opts) { logErrorForInvalidProfileAccess(user); if (DEBUG) { if (DEBUG) { Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier()); Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier()); } } Loading @@ -486,6 +500,7 @@ public class LauncherApps { */ */ public void startAppDetailsActivity(ComponentName component, UserHandle user, public void startAppDetailsActivity(ComponentName component, UserHandle user, Rect sourceBounds, Bundle opts) { Rect sourceBounds, Bundle opts) { logErrorForInvalidProfileAccess(user); try { try { mService.showAppDetailsAsUser(mContext.getPackageName(), mService.showAppDetailsAsUser(mContext.getPackageName(), component, sourceBounds, opts, user); component, sourceBounds, opts, user); Loading @@ -507,6 +522,7 @@ public class LauncherApps { */ */ public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName, public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName, @NonNull UserHandle user) { @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return convertToActivityList(mService.getShortcutConfigActivities( return convertToActivityList(mService.getShortcutConfigActivities( mContext.getPackageName(), packageName, user), mContext.getPackageName(), packageName, user), Loading Loading @@ -553,6 +569,7 @@ public class LauncherApps { * @see Intent#ACTION_CREATE_SHORTCUT * @see Intent#ACTION_CREATE_SHORTCUT * @see android.app.Activity#startIntentSenderForResult * @see android.app.Activity#startIntentSenderForResult */ */ @Nullable public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) { public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) { try { try { return mService.getShortcutConfigActivityIntent( return mService.getShortcutConfigActivityIntent( Loading @@ -571,6 +588,7 @@ public class LauncherApps { * @return true if the package exists and is enabled. * @return true if the package exists and is enabled. */ */ public boolean isPackageEnabled(String packageName, UserHandle user) { public boolean isPackageEnabled(String packageName, UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return mService.isPackageEnabled(mContext.getPackageName(), packageName, user); return mService.isPackageEnabled(mContext.getPackageName(), packageName, user); } catch (RemoteException re) { } catch (RemoteException re) { Loading @@ -591,6 +609,7 @@ public class LauncherApps { */ */ public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags, public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags, UserHandle user) { UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return mService.getApplicationInfo(mContext.getPackageName(), packageName, flags, user); return mService.getApplicationInfo(mContext.getPackageName(), packageName, flags, user); } catch (RemoteException re) { } catch (RemoteException re) { Loading @@ -607,6 +626,7 @@ public class LauncherApps { * @return true if the activity exists and is enabled. * @return true if the activity exists and is enabled. */ */ public boolean isActivityEnabled(ComponentName component, UserHandle user) { public boolean isActivityEnabled(ComponentName component, UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return mService.isActivityEnabled(mContext.getPackageName(), component, user); return mService.isActivityEnabled(mContext.getPackageName(), component, user); } catch (RemoteException re) { } catch (RemoteException re) { Loading Loading @@ -656,6 +676,7 @@ public class LauncherApps { @Nullable @Nullable public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query, public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query, @NonNull UserHandle user) { @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return mService.getShortcuts(mContext.getPackageName(), return mService.getShortcuts(mContext.getPackageName(), query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity, 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, public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds, @NonNull UserHandle user) { @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user); mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user); } catch (RemoteException e) { } catch (RemoteException e) { Loading Loading @@ -866,6 +888,8 @@ public class LauncherApps { public void startShortcut(@NonNull String packageName, @NonNull String shortcutId, public void startShortcut(@NonNull String packageName, @NonNull String shortcutId, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions, @NonNull UserHandle user) { @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions, startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions, user.getIdentifier()); user.getIdentifier()); } } Loading services/core/java/com/android/server/pm/LauncherAppsService.java +95 −58 Original line number Original line Diff line number Diff line Loading @@ -64,6 +64,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemService; import java.util.ArrayList; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.List; /** /** Loading Loading @@ -216,29 +217,35 @@ public class LauncherAppsService extends SystemService { } } } } /** /** See {@link #canAccessProfile(String, int, String)} */ * Checks if the caller is in the same group as the userToCheck. private boolean canAccessProfile( */ String callingPackage, UserHandle targetUser, String message) { private void ensureInUserProfiles( return canAccessProfile(callingPackage, targetUser.getIdentifier(), message); String callingPackage, UserHandle userToCheck, String message) { ensureInUserProfiles(callingPackage, userToCheck.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(); final int callingUserId = injectCallingUserId(); if (targetUserId == callingUserId) return; if (targetUserId == callingUserId) return true; long ident = injectClearCallingIdentity(); long ident = injectClearCallingIdentity(); try { try { UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); if (callingUserInfo.isManagedProfile()) { 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 " Slog.wtfStack(TAG, message + " by " + callingPackage + " for another profile " + targetUserId + " from " + callingUserId); + targetUserId + " from " + callingUserId); return false; } } UserInfo targetUserInfo = mUm.getUserInfo(targetUserId); UserInfo targetUserInfo = mUm.getUserInfo(targetUserId); Loading @@ -250,6 +257,7 @@ public class LauncherAppsService extends SystemService { } finally { } finally { injectRestoreCallingIdentity(ident); injectRestoreCallingIdentity(ident); } } return true; } } @VisibleForTesting // We override it in unit tests @VisibleForTesting // We override it in unit tests Loading Loading @@ -301,7 +309,9 @@ public class LauncherAppsService extends SystemService { public ActivityInfo resolveActivity( public ActivityInfo resolveActivity( String callingPackage, ComponentName component, UserHandle user) String callingPackage, ComponentName component, UserHandle user) throws RemoteException { throws RemoteException { ensureInUserProfiles(callingPackage, user, "Cannot resolve activity"); if (!canAccessProfile(callingPackage, user, "Cannot resolve activity")) { return null; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { return null; return null; } } Loading @@ -328,7 +338,9 @@ public class LauncherAppsService extends SystemService { private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage, private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage, Intent intent, UserHandle user) { Intent intent, UserHandle user) { ensureInUserProfiles(callingPackage, user, "Cannot retrieve activities"); if (!canAccessProfile(callingPackage, user, "Cannot retrieve activities")) { return null; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { return null; return null; } } Loading @@ -348,7 +360,10 @@ public class LauncherAppsService extends SystemService { @Override @Override public IntentSender getShortcutConfigActivityIntent(String callingPackage, public IntentSender getShortcutConfigActivityIntent(String callingPackage, ComponentName component, UserHandle user) throws RemoteException { ComponentName component, UserHandle user) throws RemoteException { ensureShortcutPermission(callingPackage, user); ensureShortcutPermission(callingPackage); if (!canAccessProfile(callingPackage, user, "Cannot check package")) { return null; } Preconditions.checkNotNull(component); Preconditions.checkNotNull(component); Preconditions.checkArgument(isUserEnabled(user), "User not enabled"); 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); Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component); final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity(); try { try { return PendingIntent.getActivityAsUser( final PendingIntent pi = PendingIntent.getActivityAsUser( mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT, | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT, null, user) null, user); .getIntentSender(); return pi == null ? null : pi.getIntentSender(); } finally { } finally { Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity); } } Loading @@ -369,7 +384,9 @@ public class LauncherAppsService extends SystemService { @Override @Override public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user) public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user) throws RemoteException { throws RemoteException { ensureInUserProfiles(callingPackage, user, "Cannot check package"); if (!canAccessProfile(callingPackage, user, "Cannot check package")) { return false; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { return false; return false; } } Loading @@ -391,7 +408,9 @@ public class LauncherAppsService extends SystemService { public ApplicationInfo getApplicationInfo( public ApplicationInfo getApplicationInfo( String callingPackage, String packageName, int flags, UserHandle user) String callingPackage, String packageName, int flags, UserHandle user) throws RemoteException { throws RemoteException { ensureInUserProfiles(callingPackage, user, "Cannot check package"); if (!canAccessProfile(callingPackage, user, "Cannot check package")) { return null; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { return null; return null; } } Loading @@ -407,14 +426,8 @@ public class LauncherAppsService extends SystemService { } } } } private void ensureShortcutPermission(@NonNull String callingPackage, UserHandle user) { private void ensureShortcutPermission(@NonNull String callingPackage) { ensureShortcutPermission(callingPackage, user.getIdentifier()); } private void ensureShortcutPermission(@NonNull String callingPackage, int userId) { verifyCallingPackage(callingPackage); verifyCallingPackage(callingPackage); ensureInUserProfiles(callingPackage, userId, "Cannot access shortcuts"); if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), callingPackage)) { callingPackage)) { throw new SecurityException("Caller can't access shortcut information"); throw new SecurityException("Caller can't access shortcut information"); Loading @@ -424,10 +437,11 @@ public class LauncherAppsService extends SystemService { @Override @Override public ParceledListSlice getShortcuts(String callingPackage, long changedSince, public ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName, List shortcutIds, ComponentName componentName, int flags, String packageName, List shortcutIds, ComponentName componentName, int flags, UserHandle user) { UserHandle targetUser) { ensureShortcutPermission(callingPackage, user); ensureShortcutPermission(callingPackage); if (!isUserEnabled(user)) { if (!canAccessProfile(callingPackage, targetUser, "Cannot get shortcuts") return new ParceledListSlice<>(new ArrayList(0)); || !isUserEnabled(targetUser)) { return new ParceledListSlice<>(Collections.EMPTY_LIST); } } if (shortcutIds != null && packageName == null) { if (shortcutIds != null && packageName == null) { throw new IllegalArgumentException( throw new IllegalArgumentException( Loading @@ -438,44 +452,53 @@ public class LauncherAppsService extends SystemService { return new ParceledListSlice<>((List<ShortcutInfo>) return new ParceledListSlice<>((List<ShortcutInfo>) mShortcutServiceInternal.getShortcuts(getCallingUserId(), mShortcutServiceInternal.getShortcuts(getCallingUserId(), callingPackage, changedSince, packageName, shortcutIds, callingPackage, changedSince, packageName, shortcutIds, componentName, flags, user.getIdentifier())); componentName, flags, targetUser.getIdentifier())); } } @Override @Override public void pinShortcuts(String callingPackage, String packageName, List<String> ids, public void pinShortcuts(String callingPackage, String packageName, List<String> ids, UserHandle user) { UserHandle targetUser) { ensureShortcutPermission(callingPackage, user); ensureShortcutPermission(callingPackage); if (!isUserEnabled(user)) { if (!canAccessProfile(callingPackage, targetUser, "Cannot pin shortcuts")) { return; } if (!isUserEnabled(targetUser)) { throw new IllegalStateException("Cannot pin shortcuts for disabled profile " throw new IllegalStateException("Cannot pin shortcuts for disabled profile " + user); + targetUser); } } mShortcutServiceInternal.pinShortcuts(getCallingUserId(), mShortcutServiceInternal.pinShortcuts(getCallingUserId(), callingPackage, packageName, ids, user.getIdentifier()); callingPackage, packageName, ids, targetUser.getIdentifier()); } } @Override @Override public int getShortcutIconResId(String callingPackage, String packageName, String id, public int getShortcutIconResId(String callingPackage, String packageName, String id, int userId) { int targetUserId) { ensureShortcutPermission(callingPackage, userId); ensureShortcutPermission(callingPackage); if (!isUserEnabled(userId)) { if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) { return 0; } if (!isUserEnabled(targetUserId)) { return 0; return 0; } } return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(), return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(), callingPackage, packageName, id, userId); callingPackage, packageName, id, targetUserId); } } @Override @Override public ParcelFileDescriptor getShortcutIconFd(String callingPackage, public ParcelFileDescriptor getShortcutIconFd(String callingPackage, String packageName, String id, int userId) { String packageName, String id, int targetUserId) { ensureShortcutPermission(callingPackage, userId); ensureShortcutPermission(callingPackage); if (!isUserEnabled(userId)) { if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) { return null; } if (!isUserEnabled(targetUserId)) { return null; return null; } } return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(), return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(), callingPackage, packageName, id, userId); callingPackage, packageName, id, targetUserId); } } @Override @Override Loading @@ -487,23 +510,27 @@ public class LauncherAppsService extends SystemService { @Override @Override public boolean startShortcut(String callingPackage, String packageName, String shortcutId, public boolean startShortcut(String callingPackage, String packageName, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, int userId) { Rect sourceBounds, Bundle startActivityOptions, int targetUserId) { verifyCallingPackage(callingPackage); verifyCallingPackage(callingPackage); ensureInUserProfiles(callingPackage, userId, "Cannot start activity"); if (!canAccessProfile(callingPackage, targetUserId, "Cannot start activity")) { return false; if (!isUserEnabled(userId)) { } if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) { return false; } if (!isUserEnabled(targetUserId)) { throw new IllegalStateException("Cannot start a shortcut for disabled profile " throw new IllegalStateException("Cannot start a shortcut for disabled profile " + userId); + targetUserId); } } // Even without the permission, pinned shortcuts are always launchable. // Even without the permission, pinned shortcuts are always launchable. if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(), if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(), callingPackage, packageName, shortcutId, userId)) { callingPackage, packageName, shortcutId, targetUserId)) { ensureShortcutPermission(callingPackage, userId); ensureShortcutPermission(callingPackage); } } final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( getCallingUserId(), callingPackage, packageName, shortcutId, userId); getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId); if (intents == null || intents.length == 0) { if (intents == null || intents.length == 0) { return false; return false; } } Loading @@ -513,7 +540,7 @@ public class LauncherAppsService extends SystemService { intents[0].setSourceBounds(sourceBounds); intents[0].setSourceBounds(sourceBounds); return startShortcutIntentsAsPublisher( return startShortcutIntentsAsPublisher( intents, packageName, startActivityOptions, userId); intents, packageName, startActivityOptions, targetUserId); } } private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents, private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents, Loading Loading @@ -543,7 +570,9 @@ public class LauncherAppsService extends SystemService { public boolean isActivityEnabled( public boolean isActivityEnabled( String callingPackage, ComponentName component, UserHandle user) String callingPackage, ComponentName component, UserHandle user) throws RemoteException { throws RemoteException { ensureInUserProfiles(callingPackage , user, "Cannot check component"); if (!canAccessProfile(callingPackage , user, "Cannot check component")) { return false; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { return false; return false; } } Loading @@ -565,7 +594,9 @@ public class LauncherAppsService extends SystemService { public void startActivityAsUser(String callingPackage, public void startActivityAsUser(String callingPackage, ComponentName component, Rect sourceBounds, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { Bundle opts, UserHandle user) throws RemoteException { ensureInUserProfiles(callingPackage, user, "Cannot start activity"); if (!canAccessProfile(callingPackage, user, "Cannot start activity")) { return; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { throw new IllegalStateException("Cannot start activity for disabled profile " + user); throw new IllegalStateException("Cannot start activity for disabled profile " + user); } } Loading Loading @@ -618,7 +649,9 @@ public class LauncherAppsService extends SystemService { @Override @Override public void showAppDetailsAsUser(String callingPackage, ComponentName component, public void showAppDetailsAsUser(String callingPackage, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { 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)) { if (!isUserEnabled(user)) { throw new IllegalStateException("Cannot show app details for disabled profile " throw new IllegalStateException("Cannot show app details for disabled profile " + user); + user); Loading @@ -642,9 +675,13 @@ public class LauncherAppsService extends SystemService { private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, String debugMsg) { String debugMsg) { if (user.getIdentifier() == listeningUser.getIdentifier()) { 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; 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(); long ident = injectClearCallingIdentity(); try { try { UserInfo userInfo = mUm.getUserInfo(user.getIdentifier()); UserInfo userInfo = mUm.getUserInfo(user.getIdentifier()); Loading services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +17 −1 Original line number Original line 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_0 = UserHandle.USER_SYSTEM; protected static final int USER_10 = 10; protected static final int USER_10 = 10; protected static final int USER_11 = 11; 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_0 = UserHandle.of(USER_0); protected static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10); 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_11 = UserHandle.of(USER_11); protected static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0); 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( protected static final UserInfo USER_INFO_0 = withProfileGroupId( new UserInfo(USER_0, "user0", new UserInfo(USER_0, "user0", Loading @@ -630,6 +632,10 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected static final UserInfo USER_INFO_P0 = withProfileGroupId( protected static final UserInfo USER_INFO_P0 = withProfileGroupId( new UserInfo(USER_P0, "userP0", UserInfo.FLAG_INITIALIZED), 0); 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 = protected BiPredicate<String, Integer> mDefaultLauncherChecker = (callingPackage, userId) -> (callingPackage, userId) -> LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage) 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_10, USER_INFO_10); mUserInfos.put(USER_11, USER_INFO_11); mUserInfos.put(USER_11, USER_INFO_11); mUserInfos.put(USER_P0, USER_INFO_P0); mUserInfos.put(USER_P0, USER_INFO_P0); mUserInfos.put(USER_P1, USER_INFO_P1); // Set up isUserRunning and isUserUnlocked. // Set up isUserRunning and isUserUnlocked. when(mMockUserManager.isUserRunning(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( when(mMockUserManager.isUserRunning(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( Loading Loading @@ -775,6 +782,13 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { assertNotNull(parent); assertNotNull(parent); return 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( when(mMockActivityManagerInternal.getUidProcessState(anyInt())).thenReturn( ActivityManager.PROCESS_STATE_CACHED_EMPTY); ActivityManager.PROCESS_STATE_CACHED_EMPTY); Loading @@ -784,12 +798,14 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { mRunningUsers.put(USER_10, false); mRunningUsers.put(USER_10, false); mRunningUsers.put(USER_11, false); mRunningUsers.put(USER_11, false); mRunningUsers.put(USER_P0, true); mRunningUsers.put(USER_P0, true); mRunningUsers.put(USER_P1, true); // Unlock all users by default. // Unlock all users by default. mUnlockedUsers.put(USER_0, true); mUnlockedUsers.put(USER_0, true); mUnlockedUsers.put(USER_10, true); mUnlockedUsers.put(USER_10, true); mUnlockedUsers.put(USER_11, true); mUnlockedUsers.put(USER_11, true); mUnlockedUsers.put(USER_P0, true); mUnlockedUsers.put(USER_P0, true); mUnlockedUsers.put(USER_P1, true); // Set up resources // Set up resources setUpAppResources(); 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 Original line Diff line number Diff line Loading @@ -127,9 +127,10 @@ public class LauncherApps { public static final String EXTRA_PIN_ITEM_REQUEST = public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST"; "android.content.pm.extra.PIN_ITEM_REQUEST"; private Context mContext; private final Context mContext; private ILauncherApps mService; private final ILauncherApps mService; private PackageManager mPm; private final PackageManager mPm; private final UserManager mUserManager; private List<CallbackMessageHandler> mCallbacks private List<CallbackMessageHandler> mCallbacks = new ArrayList<CallbackMessageHandler>(); = new ArrayList<CallbackMessageHandler>(); Loading Loading @@ -387,6 +388,7 @@ public class LauncherApps { mContext = context; mContext = context; mService = service; mService = service; mPm = context.getPackageManager(); mPm = context.getPackageManager(); mUserManager = context.getSystemService(UserManager.class); } } /** @hide */ /** @hide */ Loading @@ -396,6 +398,16 @@ public class LauncherApps { ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE))); 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. * 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. * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would. */ */ public List<UserHandle> getProfiles() { public List<UserHandle> getProfiles() { final UserManager um = mContext.getSystemService(UserManager.class); if (mUserManager.isManagedProfile()) { if (um.isManagedProfile()) { // If it's a managed profile, only return the current profile. // If it's a managed profile, only return the current profile. final List result = new ArrayList(1); final List result = new ArrayList(1); result.add(android.os.Process.myUserHandle()); result.add(android.os.Process.myUserHandle()); return result; return result; } else { } 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. * @return List of launchable activities. Can be an empty list but will not be null. */ */ public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) { public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(), return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(), packageName, user), user); packageName, user), user); Loading @@ -441,6 +453,7 @@ public class LauncherApps { * @return An activity info object if there is a match. * @return An activity info object if there is a match. */ */ public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) { public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(), ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(), intent.getComponent(), user); intent.getComponent(), user); Loading @@ -464,6 +477,7 @@ public class LauncherApps { */ */ public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds, public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds, Bundle opts) { Bundle opts) { logErrorForInvalidProfileAccess(user); if (DEBUG) { if (DEBUG) { Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier()); Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier()); } } Loading @@ -486,6 +500,7 @@ public class LauncherApps { */ */ public void startAppDetailsActivity(ComponentName component, UserHandle user, public void startAppDetailsActivity(ComponentName component, UserHandle user, Rect sourceBounds, Bundle opts) { Rect sourceBounds, Bundle opts) { logErrorForInvalidProfileAccess(user); try { try { mService.showAppDetailsAsUser(mContext.getPackageName(), mService.showAppDetailsAsUser(mContext.getPackageName(), component, sourceBounds, opts, user); component, sourceBounds, opts, user); Loading @@ -507,6 +522,7 @@ public class LauncherApps { */ */ public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName, public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName, @NonNull UserHandle user) { @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return convertToActivityList(mService.getShortcutConfigActivities( return convertToActivityList(mService.getShortcutConfigActivities( mContext.getPackageName(), packageName, user), mContext.getPackageName(), packageName, user), Loading Loading @@ -553,6 +569,7 @@ public class LauncherApps { * @see Intent#ACTION_CREATE_SHORTCUT * @see Intent#ACTION_CREATE_SHORTCUT * @see android.app.Activity#startIntentSenderForResult * @see android.app.Activity#startIntentSenderForResult */ */ @Nullable public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) { public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) { try { try { return mService.getShortcutConfigActivityIntent( return mService.getShortcutConfigActivityIntent( Loading @@ -571,6 +588,7 @@ public class LauncherApps { * @return true if the package exists and is enabled. * @return true if the package exists and is enabled. */ */ public boolean isPackageEnabled(String packageName, UserHandle user) { public boolean isPackageEnabled(String packageName, UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return mService.isPackageEnabled(mContext.getPackageName(), packageName, user); return mService.isPackageEnabled(mContext.getPackageName(), packageName, user); } catch (RemoteException re) { } catch (RemoteException re) { Loading @@ -591,6 +609,7 @@ public class LauncherApps { */ */ public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags, public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags, UserHandle user) { UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return mService.getApplicationInfo(mContext.getPackageName(), packageName, flags, user); return mService.getApplicationInfo(mContext.getPackageName(), packageName, flags, user); } catch (RemoteException re) { } catch (RemoteException re) { Loading @@ -607,6 +626,7 @@ public class LauncherApps { * @return true if the activity exists and is enabled. * @return true if the activity exists and is enabled. */ */ public boolean isActivityEnabled(ComponentName component, UserHandle user) { public boolean isActivityEnabled(ComponentName component, UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return mService.isActivityEnabled(mContext.getPackageName(), component, user); return mService.isActivityEnabled(mContext.getPackageName(), component, user); } catch (RemoteException re) { } catch (RemoteException re) { Loading Loading @@ -656,6 +676,7 @@ public class LauncherApps { @Nullable @Nullable public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query, public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query, @NonNull UserHandle user) { @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { return mService.getShortcuts(mContext.getPackageName(), return mService.getShortcuts(mContext.getPackageName(), query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity, 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, public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds, @NonNull UserHandle user) { @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { try { mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user); mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user); } catch (RemoteException e) { } catch (RemoteException e) { Loading Loading @@ -866,6 +888,8 @@ public class LauncherApps { public void startShortcut(@NonNull String packageName, @NonNull String shortcutId, public void startShortcut(@NonNull String packageName, @NonNull String shortcutId, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions, @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions, @NonNull UserHandle user) { @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions, startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions, user.getIdentifier()); user.getIdentifier()); } } Loading
services/core/java/com/android/server/pm/LauncherAppsService.java +95 −58 Original line number Original line Diff line number Diff line Loading @@ -64,6 +64,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemService; import java.util.ArrayList; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.List; /** /** Loading Loading @@ -216,29 +217,35 @@ public class LauncherAppsService extends SystemService { } } } } /** /** See {@link #canAccessProfile(String, int, String)} */ * Checks if the caller is in the same group as the userToCheck. private boolean canAccessProfile( */ String callingPackage, UserHandle targetUser, String message) { private void ensureInUserProfiles( return canAccessProfile(callingPackage, targetUser.getIdentifier(), message); String callingPackage, UserHandle userToCheck, String message) { ensureInUserProfiles(callingPackage, userToCheck.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(); final int callingUserId = injectCallingUserId(); if (targetUserId == callingUserId) return; if (targetUserId == callingUserId) return true; long ident = injectClearCallingIdentity(); long ident = injectClearCallingIdentity(); try { try { UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); UserInfo callingUserInfo = mUm.getUserInfo(callingUserId); if (callingUserInfo.isManagedProfile()) { 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 " Slog.wtfStack(TAG, message + " by " + callingPackage + " for another profile " + targetUserId + " from " + callingUserId); + targetUserId + " from " + callingUserId); return false; } } UserInfo targetUserInfo = mUm.getUserInfo(targetUserId); UserInfo targetUserInfo = mUm.getUserInfo(targetUserId); Loading @@ -250,6 +257,7 @@ public class LauncherAppsService extends SystemService { } finally { } finally { injectRestoreCallingIdentity(ident); injectRestoreCallingIdentity(ident); } } return true; } } @VisibleForTesting // We override it in unit tests @VisibleForTesting // We override it in unit tests Loading Loading @@ -301,7 +309,9 @@ public class LauncherAppsService extends SystemService { public ActivityInfo resolveActivity( public ActivityInfo resolveActivity( String callingPackage, ComponentName component, UserHandle user) String callingPackage, ComponentName component, UserHandle user) throws RemoteException { throws RemoteException { ensureInUserProfiles(callingPackage, user, "Cannot resolve activity"); if (!canAccessProfile(callingPackage, user, "Cannot resolve activity")) { return null; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { return null; return null; } } Loading @@ -328,7 +338,9 @@ public class LauncherAppsService extends SystemService { private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage, private ParceledListSlice<ResolveInfo> queryActivitiesForUser(String callingPackage, Intent intent, UserHandle user) { Intent intent, UserHandle user) { ensureInUserProfiles(callingPackage, user, "Cannot retrieve activities"); if (!canAccessProfile(callingPackage, user, "Cannot retrieve activities")) { return null; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { return null; return null; } } Loading @@ -348,7 +360,10 @@ public class LauncherAppsService extends SystemService { @Override @Override public IntentSender getShortcutConfigActivityIntent(String callingPackage, public IntentSender getShortcutConfigActivityIntent(String callingPackage, ComponentName component, UserHandle user) throws RemoteException { ComponentName component, UserHandle user) throws RemoteException { ensureShortcutPermission(callingPackage, user); ensureShortcutPermission(callingPackage); if (!canAccessProfile(callingPackage, user, "Cannot check package")) { return null; } Preconditions.checkNotNull(component); Preconditions.checkNotNull(component); Preconditions.checkArgument(isUserEnabled(user), "User not enabled"); 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); Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component); final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity(); try { try { return PendingIntent.getActivityAsUser( final PendingIntent pi = PendingIntent.getActivityAsUser( mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT, | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT, null, user) null, user); .getIntentSender(); return pi == null ? null : pi.getIntentSender(); } finally { } finally { Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity); } } Loading @@ -369,7 +384,9 @@ public class LauncherAppsService extends SystemService { @Override @Override public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user) public boolean isPackageEnabled(String callingPackage, String packageName, UserHandle user) throws RemoteException { throws RemoteException { ensureInUserProfiles(callingPackage, user, "Cannot check package"); if (!canAccessProfile(callingPackage, user, "Cannot check package")) { return false; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { return false; return false; } } Loading @@ -391,7 +408,9 @@ public class LauncherAppsService extends SystemService { public ApplicationInfo getApplicationInfo( public ApplicationInfo getApplicationInfo( String callingPackage, String packageName, int flags, UserHandle user) String callingPackage, String packageName, int flags, UserHandle user) throws RemoteException { throws RemoteException { ensureInUserProfiles(callingPackage, user, "Cannot check package"); if (!canAccessProfile(callingPackage, user, "Cannot check package")) { return null; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { return null; return null; } } Loading @@ -407,14 +426,8 @@ public class LauncherAppsService extends SystemService { } } } } private void ensureShortcutPermission(@NonNull String callingPackage, UserHandle user) { private void ensureShortcutPermission(@NonNull String callingPackage) { ensureShortcutPermission(callingPackage, user.getIdentifier()); } private void ensureShortcutPermission(@NonNull String callingPackage, int userId) { verifyCallingPackage(callingPackage); verifyCallingPackage(callingPackage); ensureInUserProfiles(callingPackage, userId, "Cannot access shortcuts"); if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), callingPackage)) { callingPackage)) { throw new SecurityException("Caller can't access shortcut information"); throw new SecurityException("Caller can't access shortcut information"); Loading @@ -424,10 +437,11 @@ public class LauncherAppsService extends SystemService { @Override @Override public ParceledListSlice getShortcuts(String callingPackage, long changedSince, public ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName, List shortcutIds, ComponentName componentName, int flags, String packageName, List shortcutIds, ComponentName componentName, int flags, UserHandle user) { UserHandle targetUser) { ensureShortcutPermission(callingPackage, user); ensureShortcutPermission(callingPackage); if (!isUserEnabled(user)) { if (!canAccessProfile(callingPackage, targetUser, "Cannot get shortcuts") return new ParceledListSlice<>(new ArrayList(0)); || !isUserEnabled(targetUser)) { return new ParceledListSlice<>(Collections.EMPTY_LIST); } } if (shortcutIds != null && packageName == null) { if (shortcutIds != null && packageName == null) { throw new IllegalArgumentException( throw new IllegalArgumentException( Loading @@ -438,44 +452,53 @@ public class LauncherAppsService extends SystemService { return new ParceledListSlice<>((List<ShortcutInfo>) return new ParceledListSlice<>((List<ShortcutInfo>) mShortcutServiceInternal.getShortcuts(getCallingUserId(), mShortcutServiceInternal.getShortcuts(getCallingUserId(), callingPackage, changedSince, packageName, shortcutIds, callingPackage, changedSince, packageName, shortcutIds, componentName, flags, user.getIdentifier())); componentName, flags, targetUser.getIdentifier())); } } @Override @Override public void pinShortcuts(String callingPackage, String packageName, List<String> ids, public void pinShortcuts(String callingPackage, String packageName, List<String> ids, UserHandle user) { UserHandle targetUser) { ensureShortcutPermission(callingPackage, user); ensureShortcutPermission(callingPackage); if (!isUserEnabled(user)) { if (!canAccessProfile(callingPackage, targetUser, "Cannot pin shortcuts")) { return; } if (!isUserEnabled(targetUser)) { throw new IllegalStateException("Cannot pin shortcuts for disabled profile " throw new IllegalStateException("Cannot pin shortcuts for disabled profile " + user); + targetUser); } } mShortcutServiceInternal.pinShortcuts(getCallingUserId(), mShortcutServiceInternal.pinShortcuts(getCallingUserId(), callingPackage, packageName, ids, user.getIdentifier()); callingPackage, packageName, ids, targetUser.getIdentifier()); } } @Override @Override public int getShortcutIconResId(String callingPackage, String packageName, String id, public int getShortcutIconResId(String callingPackage, String packageName, String id, int userId) { int targetUserId) { ensureShortcutPermission(callingPackage, userId); ensureShortcutPermission(callingPackage); if (!isUserEnabled(userId)) { if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) { return 0; } if (!isUserEnabled(targetUserId)) { return 0; return 0; } } return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(), return mShortcutServiceInternal.getShortcutIconResId(getCallingUserId(), callingPackage, packageName, id, userId); callingPackage, packageName, id, targetUserId); } } @Override @Override public ParcelFileDescriptor getShortcutIconFd(String callingPackage, public ParcelFileDescriptor getShortcutIconFd(String callingPackage, String packageName, String id, int userId) { String packageName, String id, int targetUserId) { ensureShortcutPermission(callingPackage, userId); ensureShortcutPermission(callingPackage); if (!isUserEnabled(userId)) { if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) { return null; } if (!isUserEnabled(targetUserId)) { return null; return null; } } return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(), return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(), callingPackage, packageName, id, userId); callingPackage, packageName, id, targetUserId); } } @Override @Override Loading @@ -487,23 +510,27 @@ public class LauncherAppsService extends SystemService { @Override @Override public boolean startShortcut(String callingPackage, String packageName, String shortcutId, public boolean startShortcut(String callingPackage, String packageName, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, int userId) { Rect sourceBounds, Bundle startActivityOptions, int targetUserId) { verifyCallingPackage(callingPackage); verifyCallingPackage(callingPackage); ensureInUserProfiles(callingPackage, userId, "Cannot start activity"); if (!canAccessProfile(callingPackage, targetUserId, "Cannot start activity")) { return false; if (!isUserEnabled(userId)) { } if (!canAccessProfile(callingPackage, targetUserId, "Cannot access shortcuts")) { return false; } if (!isUserEnabled(targetUserId)) { throw new IllegalStateException("Cannot start a shortcut for disabled profile " throw new IllegalStateException("Cannot start a shortcut for disabled profile " + userId); + targetUserId); } } // Even without the permission, pinned shortcuts are always launchable. // Even without the permission, pinned shortcuts are always launchable. if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(), if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(), callingPackage, packageName, shortcutId, userId)) { callingPackage, packageName, shortcutId, targetUserId)) { ensureShortcutPermission(callingPackage, userId); ensureShortcutPermission(callingPackage); } } final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( getCallingUserId(), callingPackage, packageName, shortcutId, userId); getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId); if (intents == null || intents.length == 0) { if (intents == null || intents.length == 0) { return false; return false; } } Loading @@ -513,7 +540,7 @@ public class LauncherAppsService extends SystemService { intents[0].setSourceBounds(sourceBounds); intents[0].setSourceBounds(sourceBounds); return startShortcutIntentsAsPublisher( return startShortcutIntentsAsPublisher( intents, packageName, startActivityOptions, userId); intents, packageName, startActivityOptions, targetUserId); } } private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents, private boolean startShortcutIntentsAsPublisher(@NonNull Intent[] intents, Loading Loading @@ -543,7 +570,9 @@ public class LauncherAppsService extends SystemService { public boolean isActivityEnabled( public boolean isActivityEnabled( String callingPackage, ComponentName component, UserHandle user) String callingPackage, ComponentName component, UserHandle user) throws RemoteException { throws RemoteException { ensureInUserProfiles(callingPackage , user, "Cannot check component"); if (!canAccessProfile(callingPackage , user, "Cannot check component")) { return false; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { return false; return false; } } Loading @@ -565,7 +594,9 @@ public class LauncherAppsService extends SystemService { public void startActivityAsUser(String callingPackage, public void startActivityAsUser(String callingPackage, ComponentName component, Rect sourceBounds, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { Bundle opts, UserHandle user) throws RemoteException { ensureInUserProfiles(callingPackage, user, "Cannot start activity"); if (!canAccessProfile(callingPackage, user, "Cannot start activity")) { return; } if (!isUserEnabled(user)) { if (!isUserEnabled(user)) { throw new IllegalStateException("Cannot start activity for disabled profile " + user); throw new IllegalStateException("Cannot start activity for disabled profile " + user); } } Loading Loading @@ -618,7 +649,9 @@ public class LauncherAppsService extends SystemService { @Override @Override public void showAppDetailsAsUser(String callingPackage, ComponentName component, public void showAppDetailsAsUser(String callingPackage, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { 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)) { if (!isUserEnabled(user)) { throw new IllegalStateException("Cannot show app details for disabled profile " throw new IllegalStateException("Cannot show app details for disabled profile " + user); + user); Loading @@ -642,9 +675,13 @@ public class LauncherAppsService extends SystemService { private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser, String debugMsg) { String debugMsg) { if (user.getIdentifier() == listeningUser.getIdentifier()) { 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; 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(); long ident = injectClearCallingIdentity(); try { try { UserInfo userInfo = mUm.getUserInfo(user.getIdentifier()); UserInfo userInfo = mUm.getUserInfo(user.getIdentifier()); Loading
services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +17 −1 Original line number Original line 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_0 = UserHandle.USER_SYSTEM; protected static final int USER_10 = 10; protected static final int USER_10 = 10; protected static final int USER_11 = 11; 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_0 = UserHandle.of(USER_0); protected static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10); 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_11 = UserHandle.of(USER_11); protected static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0); 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( protected static final UserInfo USER_INFO_0 = withProfileGroupId( new UserInfo(USER_0, "user0", new UserInfo(USER_0, "user0", Loading @@ -630,6 +632,10 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected static final UserInfo USER_INFO_P0 = withProfileGroupId( protected static final UserInfo USER_INFO_P0 = withProfileGroupId( new UserInfo(USER_P0, "userP0", UserInfo.FLAG_INITIALIZED), 0); 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 = protected BiPredicate<String, Integer> mDefaultLauncherChecker = (callingPackage, userId) -> (callingPackage, userId) -> LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage) 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_10, USER_INFO_10); mUserInfos.put(USER_11, USER_INFO_11); mUserInfos.put(USER_11, USER_INFO_11); mUserInfos.put(USER_P0, USER_INFO_P0); mUserInfos.put(USER_P0, USER_INFO_P0); mUserInfos.put(USER_P1, USER_INFO_P1); // Set up isUserRunning and isUserUnlocked. // Set up isUserRunning and isUserUnlocked. when(mMockUserManager.isUserRunning(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( when(mMockUserManager.isUserRunning(anyInt())).thenAnswer(new AnswerWithSystemCheck<>( Loading Loading @@ -775,6 +782,13 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { assertNotNull(parent); assertNotNull(parent); return 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( when(mMockActivityManagerInternal.getUidProcessState(anyInt())).thenReturn( ActivityManager.PROCESS_STATE_CACHED_EMPTY); ActivityManager.PROCESS_STATE_CACHED_EMPTY); Loading @@ -784,12 +798,14 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { mRunningUsers.put(USER_10, false); mRunningUsers.put(USER_10, false); mRunningUsers.put(USER_11, false); mRunningUsers.put(USER_11, false); mRunningUsers.put(USER_P0, true); mRunningUsers.put(USER_P0, true); mRunningUsers.put(USER_P1, true); // Unlock all users by default. // Unlock all users by default. mUnlockedUsers.put(USER_0, true); mUnlockedUsers.put(USER_0, true); mUnlockedUsers.put(USER_10, true); mUnlockedUsers.put(USER_10, true); mUnlockedUsers.put(USER_11, true); mUnlockedUsers.put(USER_11, true); mUnlockedUsers.put(USER_P0, true); mUnlockedUsers.put(USER_P0, true); mUnlockedUsers.put(USER_P1, true); // Set up resources // Set up resources setUpAppResources(); setUpAppResources(); Loading
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +26 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes