From 2459a08f86b6d4794a8e95a08b77c4984f9a080a Mon Sep 17 00:00:00 2001 From: kholoud mohamed Date: Wed, 18 Mar 2020 12:49:32 +0000 Subject: [PATCH] Add new hidden API in CrossProfileApps and other minor changes * Added a new hidden API canUserAttemptToConfigureInteractAcrossProfiles to be used in settings. * Changed canRequestToInteractAcrossProfiles to return true when app is not whitelisted by the admin or installed in the other profile, this enables the app to navigate the user to the cross profile settings page were more information about why they can't grant the permission will be provided. Bug: 149742043 Test: atest CrossProfileAppsServiceImplRoboTest Test: atest CrossProfileAppsPermissionHostSideTest Test: CrossProfileAppsTest Change-Id: I9c7734d7ab0c7436d84a27604146ff539e1cb26a --- .../android/content/pm/CrossProfileApps.java | 29 +++++++++++++++-- .../android/content/pm/ICrossProfileApps.aidl | 1 + .../pm/CrossProfileAppsServiceImpl.java | 24 +++++++++----- .../CrossProfileAppsServiceImplRoboTest.java | 32 +++++++++++++++++++ 4 files changed, 75 insertions(+), 11 deletions(-) diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java index 179fc5c661a5f..6ba811e077ac8 100644 --- a/core/java/android/content/pm/CrossProfileApps.java +++ b/core/java/android/content/pm/CrossProfileApps.java @@ -268,15 +268,17 @@ public class CrossProfileApps { } /** - * Returns whether the calling package can request user consent to interact across profiles. + * Returns whether the calling package can request to navigate the user to + * the relevant settings page to request user consent to interact across profiles. * - *

If {@code true}, user consent can be obtained via {@link + *

If {@code true}, the navigation intent can be obtained via {@link * #createRequestInteractAcrossProfilesIntent()}. The package can then listen to {@link * #ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED} broadcasts. * *

Specifically, returns whether the following are all true: *

* + *

Note that in order for the user to be able to grant the consent, the requesting package + * must be whitelisted by the admin or the OEM and installed in the other profile. If this is + * not the case the user will be shown a message explaining why they can't grant the consent. + * *

Note that user consent could already be granted if given a return value of {@code true}. * The package's current ability to interact across profiles can be checked with {@link * #canInteractAcrossProfiles()}. @@ -421,6 +427,23 @@ public class CrossProfileApps { } } + /** + * Returns {@code true} if the given package has requested + * {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} and the user has at least one + * other profile in the same profile group. + * + *

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. + * + * @hide + */ + public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) { + try { + return mService.canUserAttemptToConfigureInteractAcrossProfiles(packageName); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } /** * For each of the packages defined in {@code previousCrossProfilePackages} but not included in * {@code newCrossProfilePackages}, resets the app-op for {@link android.Manifest.permission diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl index 4cecb30990e6c..9b0dae221538b 100644 --- a/core/java/android/content/pm/ICrossProfileApps.aidl +++ b/core/java/android/content/pm/ICrossProfileApps.aidl @@ -38,5 +38,6 @@ interface ICrossProfileApps { boolean canRequestInteractAcrossProfiles(in String callingPackage); void setInteractAcrossProfilesAppOp(in String packageName, int newMode); boolean canConfigureInteractAcrossProfiles(in String packageName); + boolean canUserAttemptToConfigureInteractAcrossProfiles(in String packageName); void resetInteractAcrossProfilesAppOps(in List packageNames); } diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java index 83da38195053a..7069818e38941 100644 --- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java @@ -249,16 +249,13 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { } private boolean canRequestInteractAcrossProfilesUnchecked(String packageName) { - List targetUserProfiles = - getTargetUserProfilesUnchecked(packageName, mInjector.getCallingUserId()); - if (targetUserProfiles.isEmpty()) { + final int[] enabledProfileIds = + mInjector.getUserManager().getEnabledProfileIds(mInjector.getCallingUserId()); + if (enabledProfileIds.length < 2) { return false; } - if (!hasRequestedAppOpPermission( - AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName)) { - return false; - } - return isCrossProfilePackageWhitelisted(packageName); + return hasRequestedAppOpPermission( + AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName); } private boolean hasRequestedAppOpPermission(String permission, String packageName) { @@ -540,6 +537,17 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { return isCrossProfilePackageWhitelisted(packageName); } + @Override + public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) { + final int[] profileIds = mInjector.getUserManager().getProfileIds( + mInjector.getCallingUserId(), /* enabledOnly= */ false); + if (profileIds.length < 2) { + return false; + } + return hasRequestedAppOpPermission( + AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName); + } + private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) { return mInjector.withCleanCallingIdentity(() -> { final int[] profileIds = diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java index fa0febd7f20f1..acdb681421785 100644 --- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java +++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java @@ -419,6 +419,38 @@ public class CrossProfileAppsServiceImplRoboTest { .isTrue(); } + @Test + public void canUserAttemptToConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsTrue() { + mockUninstallCrossProfileAppFromWorkProfile(); + assertThat(mCrossProfileAppsServiceImpl + .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) + .isTrue(); + } + + @Test + public void canUserAttemptToConfigureInteractAcrossProfiles_packageDoesNotRequestInteractAcrossProfiles_returnsFalse() + throws Exception { + mockCrossProfileAppDoesNotRequestInteractAcrossProfiles(); + assertThat(mCrossProfileAppsServiceImpl + .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) + .isFalse(); + } + + @Test + public void canUserAttemptToConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsTrue() { + mockCrossProfileAppNotWhitelisted(); + assertThat(mCrossProfileAppsServiceImpl + .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) + .isTrue(); + } + + @Test + public void canUserAttemptToConfigureInteractAcrossProfiles_returnsTrue() { + assertThat(mCrossProfileAppsServiceImpl + .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) + .isTrue(); + } + private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) { explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode); }