Loading core/java/android/app/admin/DevicePolicyManagerInternal.java +15 −3 Original line number Diff line number Diff line Loading @@ -176,18 +176,30 @@ public abstract class DevicePolicyManagerInternal { * for cross-profile communication, via {@link * DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)}.</li> * <li>The default package names that are allowed to request user consent for cross-profile * communication without being explicitly enabled by the admin , via {@link * DevicePolicyManager#setDefaultCrossProfilePackages(ComponentName, UserHandle, Set)}.</li> * communication without being explicitly enabled by the admin, via * {@link com.android.internal.R.array#cross_profile_apps} and * {@link com.android.internal.R.array#vendor_cross_profile_apps}.</li> * </ul> * * @return the combined set of whitelisted package names set via * {@link DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)} and * {@link DevicePolicyManager#setDefaultCrossProfilePackages(ComponentName, UserHandle, Set)} * {@link com.android.internal.R.array#cross_profile_apps} and * {@link com.android.internal.R.array#vendor_cross_profile_apps} * * @hide */ public abstract List<String> getAllCrossProfilePackages(); /** * Returns the default package names set by the OEM that are allowed to request user consent for * cross-profile communication without being explicitly enabled by the admin, via * {@link com.android.internal.R.array#cross_profile_apps} and * {@link com.android.internal.R.array#vendor_cross_profile_apps}. * * @hide */ public abstract List<String> getDefaultCrossProfilePackages(); /** * Sends the {@code intent} to the packages with cross profile capabilities. * Loading core/java/android/content/pm/CrossProfileApps.java +3 −0 Original line number Diff line number Diff line Loading @@ -435,6 +435,9 @@ public class CrossProfileApps { * <p>This differs from {@link #canConfigureInteractAcrossProfiles(String)} since it will * not return {@code false} if the app is not whitelisted or not installed in the other profile. * * <p>Note that platform-signed apps that are automatically granted the permission and are not * whitelisted by the OEM will not be included in this list. * * @hide */ public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) { Loading services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +38 −1 Original line number Diff line number Diff line Loading @@ -294,6 +294,12 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { .getAllCrossProfilePackages().contains(packageName)); } private boolean isCrossProfilePackageWhitelistedByDefault(String packageName) { return mInjector.withCleanCallingIdentity(() -> mInjector.getDevicePolicyManagerInternal() .getDefaultCrossProfilePackages().contains(packageName)); } private List<UserHandle> getTargetUserProfilesUnchecked( String packageName, @UserIdInt int userId) { return mInjector.withCleanCallingIdentity(() -> { Loading Loading @@ -528,6 +534,9 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { @Override public boolean canConfigureInteractAcrossProfiles(String packageName) { if (!canUserAttemptToConfigureInteractAcrossProfiles(packageName)) { return false; } if (!hasOtherProfileWithPackageInstalled(packageName, mInjector.getCallingUserId())) { return false; } Loading @@ -546,7 +555,35 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { return false; } return hasRequestedAppOpPermission( AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName); AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName) && !isPlatformSignedAppWithNonUserConfigurablePermission(packageName, profileIds); } private boolean isPlatformSignedAppWithNonUserConfigurablePermission( String packageName, int[] profileIds) { return !isCrossProfilePackageWhitelistedByDefault(packageName) && isPlatformSignedAppWithAutomaticProfilesPermission(packageName, profileIds); } /** * Only platform-signed apps can be granted INTERACT_ACROSS_PROFILES automatically without user * consent. * * Returns true if the app is automatically granted the permission in at least one profile. */ private boolean isPlatformSignedAppWithAutomaticProfilesPermission( String packageName, int[] profileIds) { for (int userId : profileIds) { final int uid = mInjector.getPackageManagerInternal().getPackageUidInternal( packageName, /* flags= */ 0, userId); if (uid == -1) { continue; } if (isPermissionGranted(Manifest.permission.INTERACT_ACROSS_PROFILES, uid)) { return true; } } return false; } private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) { Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +5 −0 Original line number Diff line number Diff line Loading @@ -12459,6 +12459,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return DevicePolicyManagerService.this.getAllCrossProfilePackages(); } @Override public List<String> getDefaultCrossProfilePackages() { return DevicePolicyManagerService.this.getDefaultCrossProfilePackages(); } /** * Sends the {@code intent} to the packages with cross profile capabilities. * services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java +24 −0 Original line number Diff line number Diff line Loading @@ -199,6 +199,12 @@ public class CrossProfileAppsServiceImplRoboTest { CROSS_PROFILE_APP_PACKAGE_NAME, PERSONAL_PROFILE_UID, PERSONAL_PROFILE_USER_ID); ShadowApplicationPackageManager.setPackageUidAsUser( CROSS_PROFILE_APP_PACKAGE_NAME, WORK_PROFILE_UID, WORK_PROFILE_USER_ID); when(mPackageManagerInternal.getPackageUidInternal( CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, PERSONAL_PROFILE_USER_ID)) .thenReturn(PERSONAL_PROFILE_UID); when(mPackageManagerInternal.getPackageUidInternal( CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, WORK_PROFILE_USER_ID)) .thenReturn(WORK_PROFILE_UID); } @Before Loading Loading @@ -455,6 +461,19 @@ public class CrossProfileAppsServiceImplRoboTest { .isTrue(); } @Test public void canUserAttemptToConfigureInteractAcrossProfiles_platformSignedAppWithAutomaticPermission_returnsFalse() { mockCrossProfileAppNotWhitelistedByOem(); shadowOf(mContext).grantPermissions( Process.myPid(), PERSONAL_PROFILE_UID, Manifest.permission.INTERACT_ACROSS_PROFILES); assertThat(mCrossProfileAppsServiceImpl .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) .isFalse(); } @Test public void canUserAttemptToConfigureInteractAcrossProfiles_returnsTrue() { assertThat(mCrossProfileAppsServiceImpl Loading Loading @@ -528,6 +547,11 @@ public class CrossProfileAppsServiceImplRoboTest { .thenReturn(new ArrayList<>()); } private void mockCrossProfileAppNotWhitelistedByOem() { when(mDevicePolicyManagerInternal.getDefaultCrossProfilePackages()) .thenReturn(new ArrayList<>()); } private boolean receivedManifestCanInteractAcrossProfilesChangedBroadcast() { final UserHandle userHandle = UserHandle.of(PERSONAL_PROFILE_USER_ID); if (!mSentUserBroadcasts.containsKey(userHandle)) { Loading Loading
core/java/android/app/admin/DevicePolicyManagerInternal.java +15 −3 Original line number Diff line number Diff line Loading @@ -176,18 +176,30 @@ public abstract class DevicePolicyManagerInternal { * for cross-profile communication, via {@link * DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)}.</li> * <li>The default package names that are allowed to request user consent for cross-profile * communication without being explicitly enabled by the admin , via {@link * DevicePolicyManager#setDefaultCrossProfilePackages(ComponentName, UserHandle, Set)}.</li> * communication without being explicitly enabled by the admin, via * {@link com.android.internal.R.array#cross_profile_apps} and * {@link com.android.internal.R.array#vendor_cross_profile_apps}.</li> * </ul> * * @return the combined set of whitelisted package names set via * {@link DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)} and * {@link DevicePolicyManager#setDefaultCrossProfilePackages(ComponentName, UserHandle, Set)} * {@link com.android.internal.R.array#cross_profile_apps} and * {@link com.android.internal.R.array#vendor_cross_profile_apps} * * @hide */ public abstract List<String> getAllCrossProfilePackages(); /** * Returns the default package names set by the OEM that are allowed to request user consent for * cross-profile communication without being explicitly enabled by the admin, via * {@link com.android.internal.R.array#cross_profile_apps} and * {@link com.android.internal.R.array#vendor_cross_profile_apps}. * * @hide */ public abstract List<String> getDefaultCrossProfilePackages(); /** * Sends the {@code intent} to the packages with cross profile capabilities. * Loading
core/java/android/content/pm/CrossProfileApps.java +3 −0 Original line number Diff line number Diff line Loading @@ -435,6 +435,9 @@ public class CrossProfileApps { * <p>This differs from {@link #canConfigureInteractAcrossProfiles(String)} since it will * not return {@code false} if the app is not whitelisted or not installed in the other profile. * * <p>Note that platform-signed apps that are automatically granted the permission and are not * whitelisted by the OEM will not be included in this list. * * @hide */ public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) { Loading
services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +38 −1 Original line number Diff line number Diff line Loading @@ -294,6 +294,12 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { .getAllCrossProfilePackages().contains(packageName)); } private boolean isCrossProfilePackageWhitelistedByDefault(String packageName) { return mInjector.withCleanCallingIdentity(() -> mInjector.getDevicePolicyManagerInternal() .getDefaultCrossProfilePackages().contains(packageName)); } private List<UserHandle> getTargetUserProfilesUnchecked( String packageName, @UserIdInt int userId) { return mInjector.withCleanCallingIdentity(() -> { Loading Loading @@ -528,6 +534,9 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { @Override public boolean canConfigureInteractAcrossProfiles(String packageName) { if (!canUserAttemptToConfigureInteractAcrossProfiles(packageName)) { return false; } if (!hasOtherProfileWithPackageInstalled(packageName, mInjector.getCallingUserId())) { return false; } Loading @@ -546,7 +555,35 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { return false; } return hasRequestedAppOpPermission( AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName); AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName) && !isPlatformSignedAppWithNonUserConfigurablePermission(packageName, profileIds); } private boolean isPlatformSignedAppWithNonUserConfigurablePermission( String packageName, int[] profileIds) { return !isCrossProfilePackageWhitelistedByDefault(packageName) && isPlatformSignedAppWithAutomaticProfilesPermission(packageName, profileIds); } /** * Only platform-signed apps can be granted INTERACT_ACROSS_PROFILES automatically without user * consent. * * Returns true if the app is automatically granted the permission in at least one profile. */ private boolean isPlatformSignedAppWithAutomaticProfilesPermission( String packageName, int[] profileIds) { for (int userId : profileIds) { final int uid = mInjector.getPackageManagerInternal().getPackageUidInternal( packageName, /* flags= */ 0, userId); if (uid == -1) { continue; } if (isPermissionGranted(Manifest.permission.INTERACT_ACROSS_PROFILES, uid)) { return true; } } return false; } private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) { Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +5 −0 Original line number Diff line number Diff line Loading @@ -12459,6 +12459,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return DevicePolicyManagerService.this.getAllCrossProfilePackages(); } @Override public List<String> getDefaultCrossProfilePackages() { return DevicePolicyManagerService.this.getDefaultCrossProfilePackages(); } /** * Sends the {@code intent} to the packages with cross profile capabilities. *
services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java +24 −0 Original line number Diff line number Diff line Loading @@ -199,6 +199,12 @@ public class CrossProfileAppsServiceImplRoboTest { CROSS_PROFILE_APP_PACKAGE_NAME, PERSONAL_PROFILE_UID, PERSONAL_PROFILE_USER_ID); ShadowApplicationPackageManager.setPackageUidAsUser( CROSS_PROFILE_APP_PACKAGE_NAME, WORK_PROFILE_UID, WORK_PROFILE_USER_ID); when(mPackageManagerInternal.getPackageUidInternal( CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, PERSONAL_PROFILE_USER_ID)) .thenReturn(PERSONAL_PROFILE_UID); when(mPackageManagerInternal.getPackageUidInternal( CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, WORK_PROFILE_USER_ID)) .thenReturn(WORK_PROFILE_UID); } @Before Loading Loading @@ -455,6 +461,19 @@ public class CrossProfileAppsServiceImplRoboTest { .isTrue(); } @Test public void canUserAttemptToConfigureInteractAcrossProfiles_platformSignedAppWithAutomaticPermission_returnsFalse() { mockCrossProfileAppNotWhitelistedByOem(); shadowOf(mContext).grantPermissions( Process.myPid(), PERSONAL_PROFILE_UID, Manifest.permission.INTERACT_ACROSS_PROFILES); assertThat(mCrossProfileAppsServiceImpl .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) .isFalse(); } @Test public void canUserAttemptToConfigureInteractAcrossProfiles_returnsTrue() { assertThat(mCrossProfileAppsServiceImpl Loading Loading @@ -528,6 +547,11 @@ public class CrossProfileAppsServiceImplRoboTest { .thenReturn(new ArrayList<>()); } private void mockCrossProfileAppNotWhitelistedByOem() { when(mDevicePolicyManagerInternal.getDefaultCrossProfilePackages()) .thenReturn(new ArrayList<>()); } private boolean receivedManifestCanInteractAcrossProfilesChangedBroadcast() { final UserHandle userHandle = UserHandle.of(PERSONAL_PROFILE_USER_ID); if (!mSentUserBroadcasts.containsKey(userHandle)) { Loading