diff options
author | Alex Kershaw <alexkershaw@google.com> | 2020-01-15 20:00:05 +0000 |
---|---|---|
committer | Alex Kershaw <alexkershaw@google.com> | 2020-01-22 13:20:24 +0000 |
commit | 4b0197d8ba2cacaed1a2b6a774c78774fdeeffdc (patch) | |
tree | e3933f538532e6aee103e81a1ef0b8171bd0aa9c | |
parent | a263d01c447f4bf5d946dfb4361ad78a5ecce7b1 (diff) |
Reset unset app-ops when the admin sets cross-profile packages.
When the admin unsets cross-profile packages, reset the
INTERACT_ACROSS_PROFILES app-op back to the default if it is no longer
configurable by the user.
Other minor changes:
- Remove the explicit app-op permission check from
setInteractAcrossProfilesAppOp, since AppOpManager performs that check
when required.
- Fix the broadcasting logic in CrossProfileAppsServiceImpl to correctly
set the component and flags.
Bug: 136249261
Bug: 148010178
Test: atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.ManagedProfileCrossProfileTest
Change-Id: Ib8b5f331fb92fc475bc95ad039adf93fac04da37
9 files changed, 257 insertions, 46 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 9a63c528f488..aeeba4c54108 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -11399,6 +11399,10 @@ public class DevicePolicyManager { * * <p>Previous calls are overridden by each subsequent call to this method. * + * <p>When previously-set cross-profile packages are missing from {@code packageNames}, the + * app-op for {@code INTERACT_ACROSS_PROFILES} will be reset for those packages. This will not + * occur for packages that are whitelisted by the OEM. + * * @param admin the {@link DeviceAdminReceiver} this request is associated with * @param packageNames the new cross-profile package names */ diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java index 48f473018127..de153d00b48b 100644 --- a/core/java/android/content/pm/CrossProfileApps.java +++ b/core/java/android/content/pm/CrossProfileApps.java @@ -34,8 +34,10 @@ import android.provider.Settings; import com.android.internal.R; import com.android.internal.util.UserIcons; +import java.util.Collection; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; /** * Class for handling cross profile operations. Apps can use this class to interact with its @@ -298,19 +300,24 @@ public class CrossProfileApps { * configurable by users in Settings. This configures it for the profile group of the calling * package. * - * <p>Before calling, check {@link #canRequestInteractAcrossProfiles()} and do not call if it is - * {@code false}. If presenting a user interface, do not allow the user to configure the app-op - * in that case. + * <p>Before calling, check {@link #canConfigureInteractAcrossProfiles(String)} and do not call + * if it is {@code false}. If presenting a user interface, do not allow the user to configure + * the app-op in that case. * * <p>The underlying app-op {@link android.app.AppOpsManager#OP_INTERACT_ACROSS_PROFILES} should * never be set directly. This method ensures that the app-op is kept in sync for the app across * each user in the profile group and that those apps are sent a broadcast when their ability to * interact across profiles changes. * - * <p>This method should be used whenever an app's ability to interact across profiles changes, - * as defined by the return value of {@link #canInteractAcrossProfiles()}. This includes user - * consent changes in Settings or during provisioning, plus changes to the admin or OEM consent - * whitelists that make the current app-op value invalid. + * <p>This method should be used directly whenever a user's action results in a change in an + * app's ability to interact across profiles, as defined by the return value of {@link + * #canInteractAcrossProfiles()}. This includes user consent changes in Settings or during + * provisioning. + * + * <p>If other changes could have affected the app's ability to interact across profiles, as + * defined by the return value of {@link #canInteractAcrossProfiles()}, such as changes to the + * admin or OEM consent whitelists, then {@link + * #resetInteractAcrossProfilesAppOpsIfInvalid(List)} should be used. * * @hide */ @@ -325,6 +332,58 @@ public class CrossProfileApps { } } + /** + * Returns whether the given package can have its ability to interact across profiles configured + * by the user. This means that every other condition to interact across profiles has been set. + * + * <p>This differs from {@link #canRequestInteractAcrossProfiles()} since it will not return + * {@code false} simply when the target profile is disabled. + * + * @hide + */ + public boolean canConfigureInteractAcrossProfiles(@NonNull String packageName) { + try { + return mService.canConfigureInteractAcrossProfiles(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 + * #INTERACT_ACROSS_PROFILES} back to its default value if it can no longer be configured by + * users in Settings, as defined by {@link #canConfigureInteractAcrossProfiles(String)}. + * + * <p>This method should be used whenever an app's ability to interact across profiles could + * have changed as a result of non-user actions, such as changes to admin or OEM consent + * whitelists. + * + * @hide + */ + @RequiresPermission( + allOf={android.Manifest.permission.MANAGE_APP_OPS_MODES, + android.Manifest.permission.INTERACT_ACROSS_USERS}) + public void resetInteractAcrossProfilesAppOps( + @NonNull Collection<String> previousCrossProfilePackages, + @NonNull Set<String> newCrossProfilePackages) { + if (previousCrossProfilePackages.isEmpty()) { + return; + } + final List<String> unsetCrossProfilePackages = + previousCrossProfilePackages.stream() + .filter(packageName -> !newCrossProfilePackages.contains(packageName)) + .collect(Collectors.toList()); + if (unsetCrossProfilePackages.isEmpty()) { + return; + } + try { + mService.resetInteractAcrossProfilesAppOps(unsetCrossProfilePackages); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + private void verifyCanAccessUser(UserHandle userHandle) { if (!getTargetUserProfiles().contains(userHandle)) { throw new SecurityException("Not allowed to access " + userHandle); diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl index 755950cd5ebe..a69b9881aa01 100644 --- a/core/java/android/content/pm/ICrossProfileApps.aidl +++ b/core/java/android/content/pm/ICrossProfileApps.aidl @@ -35,4 +35,6 @@ interface ICrossProfileApps { boolean canInteractAcrossProfiles(in String callingPackage); boolean canRequestInteractAcrossProfiles(in String callingPackage); void setInteractAcrossProfilesAppOp(in String packageName, int newMode); + boolean canConfigureInteractAcrossProfiles(in String packageName); + void resetInteractAcrossProfilesAppOps(in List<String> packageNames); }
\ No newline at end of file diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java index fc08ddeddf82..74d2efeceb63 100644 --- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java @@ -286,21 +286,21 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { } private List<UserHandle> getTargetUserProfilesUnchecked( - String callingPackage, @UserIdInt int callingUserId) { + String packageName, @UserIdInt int userId) { final long ident = mInjector.clearCallingIdentity(); try { final int[] enabledProfileIds = - mInjector.getUserManager().getEnabledProfileIds(callingUserId); + mInjector.getUserManager().getEnabledProfileIds(userId); List<UserHandle> targetProfiles = new ArrayList<>(); - for (final int userId : enabledProfileIds) { - if (userId == callingUserId) { + for (final int profileId : enabledProfileIds) { + if (profileId == userId) { continue; } - if (!isPackageEnabled(callingPackage, userId)) { + if (!isPackageEnabled(packageName, profileId)) { continue; } - targetProfiles.add(UserHandle.of(userId)); + targetProfiles.add(UserHandle.of(profileId)); } return targetProfiles; } finally { @@ -385,14 +385,9 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { "INTERACT_ACROSS_USERS or INTERACT_ACROSS_USERS_FULL is required to set the" + " app-op for interacting across profiles."); } - if (!isPermissionGranted(Manifest.permission.MANAGE_APP_OPS_MODES, callingUid)) { - throw new SecurityException( - "MANAGE_APP_OPS_MODES is required to set the app-op for interacting across" - + " profiles."); - } final int callingUserId = mInjector.getCallingUserId(); if (newMode == AppOpsManager.MODE_ALLOWED - && !canRequestInteractAcrossProfilesUnchecked(packageName, callingUserId)) { + && !canConfigureInteractAcrossProfiles(packageName)) { // The user should not be prompted for apps that cannot request to interact across // profiles. However, we return early here if required to avoid race conditions. Slog.e(TAG, "Tried to turn on the appop for interacting across profiles for invalid" @@ -441,7 +436,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { final int uid = mInjector.getPackageManager() .getPackageUidAsUser(packageName, /* flags= */ 0, userId); if (currentModeEquals(newMode, packageName, uid)) { - Slog.w(TAG,"Attempt to set mode to existing value of " + newMode + " for " + Slog.w(TAG, "Attempt to set mode to existing value of " + newMode + " for " + packageName + " on user ID " + userId); return; } @@ -462,18 +457,73 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private void sendCanInteractAcrossProfilesChangedBroadcast( String packageName, int uid, UserHandle userHandle) { - final Intent intent = new Intent(ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED) - .setPackage(packageName); - if (!appDeclaresCrossProfileAttribute(uid)) { + final Intent intent = + new Intent(ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED).setPackage(packageName); + if (appDeclaresCrossProfileAttribute(uid)) { + intent.addFlags( + Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND); + } else { intent.addFlags(FLAG_RECEIVER_REGISTERED_ONLY); } - mInjector.sendBroadcastAsUser(intent, userHandle); + for (ResolveInfo receiver : findBroadcastReceiversForUser(intent, userHandle)) { + intent.setComponent(receiver.getComponentInfo().getComponentName()); + mInjector.sendBroadcastAsUser(intent, userHandle); + } + } + + private List<ResolveInfo> findBroadcastReceiversForUser(Intent intent, UserHandle userHandle) { + return mInjector.getPackageManager() + .queryBroadcastReceiversAsUser(intent, /* flags= */ 0, userHandle); } private boolean appDeclaresCrossProfileAttribute(int uid) { return mInjector.getPackageManagerInternal().getPackage(uid).isCrossProfile(); } + @Override + public boolean canConfigureInteractAcrossProfiles(String packageName) { + if (!hasOtherProfileWithPackageInstalled(packageName, mInjector.getCallingUserId())) { + return false; + } + if (!hasRequestedAppOpPermission( + AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName)) { + return false; + } + return isCrossProfilePackageWhitelisted(packageName); + } + + private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) { + final long ident = mInjector.clearCallingIdentity(); + try { + final int[] profileIds = + mInjector.getUserManager().getProfileIds(userId, /* enabledOnly= */ false); + for (int profileId : profileIds) { + if (profileId != userId && isPackageInstalled(packageName, profileId)) { + return true; + } + } + } finally { + mInjector.restoreCallingIdentity(ident); + } + return false; + } + + @Override + public void resetInteractAcrossProfilesAppOps(List<String> packageNames) { + packageNames.forEach(this::resetInteractAcrossProfilesAppOp); + } + + private void resetInteractAcrossProfilesAppOp(String packageName) { + if (canConfigureInteractAcrossProfiles(packageName)) { + Slog.w(TAG, "Not resetting app-op for package " + packageName + + " since it is still configurable by users."); + return; + } + final String op = + AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES); + setInteractAcrossProfilesAppOp(packageName, AppOpsManager.opToDefaultMode(op)); + } + private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) { final long ident = mInjector.clearCallingIdentity(); try { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 0c79a6f611a5..bed2f239dc13 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -156,6 +156,7 @@ import android.content.IntentFilter; import android.content.PermissionChecker; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.CrossProfileApps; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; @@ -302,6 +303,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -310,6 +312,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; +import java.util.stream.Collectors; /** * Implementation of the device policy APIs. @@ -14887,12 +14890,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } Objects.requireNonNull(who, "ComponentName is null"); Objects.requireNonNull(packageNames, "Package names is null"); + final List<String> previousCrossProfilePackages; synchronized (getLockObject()) { final ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + previousCrossProfilePackages = admin.mCrossProfilePackages; admin.mCrossProfilePackages = packageNames; saveSettingsLocked(mInjector.userHandleGetCallingUserId()); } + final CrossProfileApps crossProfileApps = mContext.getSystemService(CrossProfileApps.class); + mInjector.binderWithCleanCallingIdentity( + () -> crossProfileApps.resetInteractAcrossProfilesAppOps( + previousCrossProfilePackages, new HashSet<>(packageNames))); } @Override diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java index 96ff9c1ba726..1a7b1d3f6039 100644 --- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java +++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java @@ -18,6 +18,8 @@ package com.android.server.pm; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES; +import static android.content.Intent.FLAG_RECEIVER_FOREGROUND; +import static android.content.Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND; import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY; import static android.content.pm.CrossProfileApps.ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED; @@ -37,11 +39,13 @@ import android.app.AppOpsManager.Mode; import android.app.admin.DevicePolicyManagerInternal; import android.content.ContextWrapper; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.ResolveInfo; import android.content.pm.parsing.AndroidPackage; import android.content.pm.parsing.PackageImpl; import android.os.Process; @@ -70,6 +74,7 @@ import org.robolectric.shadow.api.Shadow; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -106,6 +111,7 @@ public class CrossProfileAppsServiceImplRoboTest { MockitoAnnotations.initMocks(this); mockCrossProfileAppInstalledAndEnabledOnEachProfile(); mockCrossProfileAppRequestsInteractAcrossProfiles(); + mockCrossProfileAppRegistersBroadcastReceiver(); mockCrossProfileAppWhitelisted(); } @@ -113,19 +119,21 @@ public class CrossProfileAppsServiceImplRoboTest { // They are enabled by default, so we simply have to ensure that a package info with an // application info is returned. final PackageInfo packageInfo = buildTestPackageInfo(); + mockCrossProfileAppInstalledOnProfile( + packageInfo, PERSONAL_PROFILE_USER_ID, PERSONAL_PROFILE_UID); + mockCrossProfileAppInstalledOnProfile(packageInfo, WORK_PROFILE_USER_ID, WORK_PROFILE_UID); + } + + private void mockCrossProfileAppInstalledOnProfile( + PackageInfo packageInfo, @UserIdInt int userId, int uid) { when(mPackageManagerInternal.getPackageInfo( eq(CROSS_PROFILE_APP_PACKAGE_NAME), /* flags= */ anyInt(), /* filterCallingUid= */ anyInt(), - eq(PERSONAL_PROFILE_USER_ID))) + eq(userId))) .thenReturn(packageInfo); - when(mPackageManagerInternal.getPackageInfo( - eq(CROSS_PROFILE_APP_PACKAGE_NAME), - /* flags= */ anyInt(), - /* filterCallingUid= */ anyInt(), - eq(WORK_PROFILE_USER_ID))) - .thenReturn(packageInfo); - mockCrossProfileAndroidPackage(PackageImpl.forParsing(CROSS_PROFILE_APP_PACKAGE_NAME)); + when(mPackageManagerInternal.getPackage(uid)) + .thenReturn(PackageImpl.forParsing(CROSS_PROFILE_APP_PACKAGE_NAME)); } private PackageInfo buildTestPackageInfo() { @@ -140,6 +148,31 @@ public class CrossProfileAppsServiceImplRoboTest { .thenReturn(new String[] {CROSS_PROFILE_APP_PACKAGE_NAME}); } + private void mockCrossProfileAppRegistersBroadcastReceiver() { + final ShadowApplicationPackageManager shadowApplicationPackageManager = + Shadow.extract(mPackageManager); + final Intent baseIntent = + new Intent(ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED) + .setPackage(CROSS_PROFILE_APP_PACKAGE_NAME); + final Intent manifestIntent = + new Intent(baseIntent) + .setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND + | Intent.FLAG_RECEIVER_FOREGROUND); + final Intent registeredIntent = + new Intent(baseIntent).setFlags(FLAG_RECEIVER_REGISTERED_ONLY); + final List<ResolveInfo> resolveInfos = Lists.newArrayList(buildTestResolveInfo()); + shadowApplicationPackageManager.setResolveInfosForIntent(manifestIntent, resolveInfos); + shadowApplicationPackageManager.setResolveInfosForIntent(registeredIntent, resolveInfos); + } + + private ResolveInfo buildTestResolveInfo() { + final ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.activityInfo = new ActivityInfo(); + resolveInfo.activityInfo.packageName = CROSS_PROFILE_APP_PACKAGE_NAME; + resolveInfo.activityInfo.name = CROSS_PROFILE_APP_PACKAGE_NAME + ".Receiver"; + return resolveInfo; + } + private void mockCrossProfileAppWhitelisted() { when(mDevicePolicyManagerInternal.getAllCrossProfilePackages()) .thenReturn(Lists.newArrayList(CROSS_PROFILE_APP_PACKAGE_NAME)); @@ -191,16 +224,6 @@ public class CrossProfileAppsServiceImplRoboTest { } @Test - public void setInteractAcrossProfilesAppOp_missingManageAppOpsModes_throwsSecurityException() { - denyPermissions(Manifest.permission.MANAGE_APP_OPS_MODES); - try { - mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp( - CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED); - fail(); - } catch (SecurityException expected) {} - } - - @Test public void setInteractAcrossProfilesAppOp_setsAppOp() { mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp( CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED); @@ -294,6 +317,54 @@ public class CrossProfileAppsServiceImplRoboTest { assertThat(receivedManifestCanInteractAcrossProfilesChangedBroadcast()).isTrue(); } + @Test + public void canConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsFalse() { + mockUninstallCrossProfileAppFromWorkProfile(); + assertThat(mCrossProfileAppsServiceImpl + .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) + .isFalse(); + } + + private void mockUninstallCrossProfileAppFromWorkProfile() { + when(mPackageManagerInternal.getPackageInfo( + eq(CROSS_PROFILE_APP_PACKAGE_NAME), + /* flags= */ anyInt(), + /* filterCallingUid= */ anyInt(), + eq(WORK_PROFILE_USER_ID))) + .thenReturn(null); + when(mPackageManagerInternal.getPackage(WORK_PROFILE_UID)).thenReturn(null); + } + + @Test + public void canConfigureInteractAcrossProfiles_packageDoesNotRequestInteractAcrossProfiles_returnsFalse() + throws Exception { + mockCrossProfileAppDoesNotRequestInteractAcrossProfiles(); + assertThat(mCrossProfileAppsServiceImpl + .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) + .isFalse(); + } + + private void mockCrossProfileAppDoesNotRequestInteractAcrossProfiles() throws Exception { + final String permissionName = Manifest.permission.INTERACT_ACROSS_PROFILES; + when(mIPackageManager.getAppOpPermissionPackages(permissionName)) + .thenReturn(new String[] {}); + } + + @Test + public void canConfigureInteractAcrossProfiles_packageNotWhitelisted_returnsFalse() { + mockCrossProfileAppNotWhitelisted(); + assertThat(mCrossProfileAppsServiceImpl + .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) + .isFalse(); + } + + @Test + public void canConfigureInteractAcrossProfiles_returnsTrue() { + assertThat(mCrossProfileAppsServiceImpl + .canConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) + .isTrue(); + } + private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) { explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode); } @@ -311,7 +382,6 @@ public class CrossProfileAppsServiceImplRoboTest { shadowOf(mContext).denyPermissions(Process.myPid(), CALLING_UID, permissions); } - private @Mode int getCrossProfileAppOp() { return getCrossProfileAppOp(PERSONAL_PROFILE_UID); } @@ -365,10 +435,12 @@ public class CrossProfileAppsServiceImplRoboTest { } private boolean isBroadcastManifestCanInteractAcrossProfilesChanged(Intent intent) { - // The manifest check is negative since the FLAG_RECEIVER_REGISTERED_ONLY flag means that - // manifest receivers can NOT receive the broadcast. return isBroadcastCanInteractAcrossProfilesChanged(intent) - && (intent.getFlags() & FLAG_RECEIVER_REGISTERED_ONLY) == 0; + && (intent.getFlags() & FLAG_RECEIVER_REGISTERED_ONLY) == 0 + && (intent.getFlags() & FLAG_RECEIVER_INCLUDE_BACKGROUND) != 0 + && (intent.getFlags() & FLAG_RECEIVER_FOREGROUND) != 0 + && intent.getComponent() != null + && intent.getComponent().getPackageName().equals(CROSS_PROFILE_APP_PACKAGE_NAME); } private void declareCrossProfileAttributeOnCrossProfileApp(boolean value) { diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java index 1443eabf07d5..aea36e555ad7 100644 --- a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java +++ b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java @@ -19,7 +19,10 @@ package com.android.server.testing.shadows; import static android.content.pm.PackageManager.NameNotFoundException; import android.app.ApplicationPackageManager; +import android.content.Intent; import android.content.pm.PackageInfo; +import android.content.pm.ResolveInfo; +import android.os.UserHandle; import android.util.ArrayMap; import org.robolectric.annotation.Implements; @@ -100,6 +103,13 @@ public class ShadowApplicationPackageManager return sPackageUids.get(packageName); } + @Override + protected List<ResolveInfo> queryBroadcastReceiversAsUser( + Intent intent, int flags, UserHandle userHandle) { + // Currently does not handle multi-user. + return queryBroadcastReceivers(intent, flags); + } + /** Clear package state. */ @Resetter public static void reset() { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 6cf6b67430ae..12228c19ca00 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -221,6 +221,8 @@ public class DpmMockContext extends MockContext { return mMockSystemServices.telephonyManager; case Context.APP_OPS_SERVICE: return mMockSystemServices.appOpsManager; + case Context.CROSS_PROFILE_APPS_SERVICE: + return mMockSystemServices.crossProfileApps; } throw new UnsupportedOperationException(); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index b9fb1aab65ba..37d40811571f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -42,6 +42,7 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.CrossProfileApps; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; @@ -120,6 +121,7 @@ public class MockSystemServices { public final TimeDetector timeDetector; public final TimeZoneDetector timeZoneDetector; public final KeyChain.KeyChainConnection keyChainConnection; + public final CrossProfileApps crossProfileApps; public final PersistentDataBlockManagerInternal persistentDataBlockManagerInternal; public final AppOpsManager appOpsManager; /** Note this is a partial mock, not a real mock. */ @@ -165,6 +167,7 @@ public class MockSystemServices { timeDetector = mock(TimeDetector.class); timeZoneDetector = mock(TimeZoneDetector.class); keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS); + crossProfileApps = mock(CrossProfileApps.class); persistentDataBlockManagerInternal = mock(PersistentDataBlockManagerInternal.class); appOpsManager = mock(AppOpsManager.class); |