Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7a405a5 authored by Alex Kershaw's avatar Alex Kershaw Committed by Android (Google) Code Review
Browse files

Merge "Give new permission to set cross-profile app-op to ManagedProvisioning"

parents 58e6d8c1 0124a098
Loading
Loading
Loading
Loading
+20 −6
Original line number Original line Diff line number Diff line
@@ -316,14 +316,21 @@ public class CrossProfileApps {
     *
     *
     * <p>If other changes could have affected the app's ability to interact across profiles, as
     * <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
     * defined by the return value of {@link #canInteractAcrossProfiles()}, such as changes to the
     * admin or OEM consent whitelists, then {@link
     * admin or OEM consent whitelists, then {@link #resetInteractAcrossProfilesAppOps(Collection,
     * #resetInteractAcrossProfilesAppOpsIfInvalid(List)} should be used.
     * Set)} should be used.
     *
     * <p>If the caller does not have the {@link android.Manifest.permission
     * #CONFIGURE_INTERACT_ACROSS_PROFILES} permission, then they must have the permissions that
     * would have been required to call {@link android.app.AppOpsManager#setMode(int, int, String,
     * int)}, which includes {@link android.Manifest.permission#MANAGE_APP_OPS_MODES}.
     *
     * <p>Also requires either {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or {@link
     * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
     *
     *
     * @hide
     * @hide
     */
     */
    @RequiresPermission(
    @RequiresPermission(
            allOf={android.Manifest.permission.MANAGE_APP_OPS_MODES,
            allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
                    android.Manifest.permission.UPDATE_APP_OPS_STATS,
                    android.Manifest.permission.INTERACT_ACROSS_USERS})
                    android.Manifest.permission.INTERACT_ACROSS_USERS})
    public void setInteractAcrossProfilesAppOp(@NonNull String packageName, @Mode int newMode) {
    public void setInteractAcrossProfilesAppOp(@NonNull String packageName, @Mode int newMode) {
        try {
        try {
@@ -360,11 +367,18 @@ public class CrossProfileApps {
     * have changed as a result of non-user actions, such as changes to admin or OEM consent
     * have changed as a result of non-user actions, such as changes to admin or OEM consent
     * whitelists.
     * whitelists.
     *
     *
     * <p>If the caller does not have the {@link android.Manifest.permission
     * #CONFIGURE_INTERACT_ACROSS_PROFILES} permission, then they must have the permissions that
     * would have been required to call {@link android.app.AppOpsManager#setMode(int, int, String,
     * int)}, which includes {@link android.Manifest.permission#MANAGE_APP_OPS_MODES}.
     *
     * <p>Also requires either {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or {@link
     * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
     *
     * @hide
     * @hide
     */
     */
    @RequiresPermission(
    @RequiresPermission(
            allOf={android.Manifest.permission.MANAGE_APP_OPS_MODES,
            allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
                    android.Manifest.permission.UPDATE_APP_OPS_STATS,
                    android.Manifest.permission.INTERACT_ACROSS_USERS})
                    android.Manifest.permission.INTERACT_ACROSS_USERS})
    public void resetInteractAcrossProfilesAppOps(
    public void resetInteractAcrossProfilesAppOps(
            @NonNull Collection<String> previousCrossProfilePackages,
            @NonNull Collection<String> previousCrossProfilePackages,
+6 −0
Original line number Original line Diff line number Diff line
@@ -2392,6 +2392,12 @@
    <permission android:name="android.permission.INTERACT_ACROSS_PROFILES"
    <permission android:name="android.permission.INTERACT_ACROSS_PROFILES"
        android:protectionLevel="signature|appop|documenter|wellbeing" />
        android:protectionLevel="signature|appop|documenter|wellbeing" />


    <!-- Allows configuring apps to have the INTERACT_ACROSS_PROFILES permission so that they can
         interact across profiles in the same profile group.
         @hide -->
    <permission android:name="android.permission.CONFIGURE_INTERACT_ACROSS_PROFILES"
        android:protectionLevel="signature" />

    <!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
    <!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
         users on the device. This permission is not available to
         users on the device. This permission is not available to
         third party applications. -->
         third party applications. -->
+1 −0
Original line number Original line Diff line number Diff line
@@ -70,6 +70,7 @@ applications that come with the platform
    <privapp-permissions package="com.android.managedprovisioning">
    <privapp-permissions package="com.android.managedprovisioning">
        <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
        <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
        <permission name="android.permission.CHANGE_CONFIGURATION"/>
        <permission name="android.permission.CHANGE_CONFIGURATION"/>
        <permission name="android.permission.CONFIGURE_INTERACT_ACROSS_PROFILES"/>
        <permission name="android.permission.CRYPT_KEEPER"/>
        <permission name="android.permission.CRYPT_KEEPER"/>
        <permission name="android.permission.DELETE_PACKAGES"/>
        <permission name="android.permission.DELETE_PACKAGES"/>
        <permission name="android.permission.INSTALL_PACKAGES"/>
        <permission name="android.permission.INSTALL_PACKAGES"/>
+72 −53
Original line number Original line Diff line number Diff line
@@ -56,6 +56,8 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
import com.android.server.LocalServices;
import com.android.server.LocalServices;
import com.android.server.appop.AppOpsService;
import com.android.server.appop.AppOpsService;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -276,19 +278,14 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
    }
    }


    private boolean isCrossProfilePackageWhitelisted(String packageName) {
    private boolean isCrossProfilePackageWhitelisted(String packageName) {
        final long ident = mInjector.clearCallingIdentity();
        return mInjector.withCleanCallingIdentity(() ->
        try {
                mInjector.getDevicePolicyManagerInternal()
            return mInjector.getDevicePolicyManagerInternal()
                        .getAllCrossProfilePackages().contains(packageName));
                    .getAllCrossProfilePackages().contains(packageName);
        } finally {
            mInjector.restoreCallingIdentity(ident);
        }
    }
    }


    private List<UserHandle> getTargetUserProfilesUnchecked(
    private List<UserHandle> getTargetUserProfilesUnchecked(
            String packageName, @UserIdInt int userId) {
            String packageName, @UserIdInt int userId) {
        final long ident = mInjector.clearCallingIdentity();
        return mInjector.withCleanCallingIdentity(() -> {
        try {
            final int[] enabledProfileIds =
            final int[] enabledProfileIds =
                    mInjector.getUserManager().getEnabledProfileIds(userId);
                    mInjector.getUserManager().getEnabledProfileIds(userId);


@@ -303,15 +300,12 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
                targetProfiles.add(UserHandle.of(profileId));
                targetProfiles.add(UserHandle.of(profileId));
            }
            }
            return targetProfiles;
            return targetProfiles;
        } finally {
        });
            mInjector.restoreCallingIdentity(ident);
        }
    }
    }


    private boolean isPackageEnabled(String packageName, @UserIdInt int userId) {
    private boolean isPackageEnabled(String packageName, @UserIdInt int userId) {
        final int callingUid = mInjector.getCallingUid();
        final int callingUid = mInjector.getCallingUid();
        final long ident = mInjector.clearCallingIdentity();
        return mInjector.withCleanCallingIdentity(() -> {
        try {
            final PackageInfo info = mInjector.getPackageManagerInternal()
            final PackageInfo info = mInjector.getPackageManagerInternal()
                    .getPackageInfo(
                    .getPackageInfo(
                            packageName,
                            packageName,
@@ -319,15 +313,12 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
                            callingUid,
                            callingUid,
                            userId);
                            userId);
            return info != null && info.applicationInfo.enabled;
            return info != null && info.applicationInfo.enabled;
        } finally {
        });
            mInjector.restoreCallingIdentity(ident);
        }
    }
    }


    private void verifyActivityCanHandleIntent(
    private void verifyActivityCanHandleIntent(
            Intent launchIntent, int callingUid, @UserIdInt int userId) {
            Intent launchIntent, int callingUid, @UserIdInt int userId) {
        final long ident = mInjector.clearCallingIdentity();
        mInjector.withCleanCallingIdentity(() -> {
        try {
            final List<ResolveInfo> activities =
            final List<ResolveInfo> activities =
                    mInjector.getPackageManagerInternal().queryIntentActivities(
                    mInjector.getPackageManagerInternal().queryIntentActivities(
                            launchIntent,
                            launchIntent,
@@ -340,9 +331,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
                return;
                return;
            }
            }
            throw new SecurityException("Activity cannot handle intent");
            throw new SecurityException("Activity cannot handle intent");
        } finally {
        });
            mInjector.restoreCallingIdentity(ident);
        }
    }
    }


    /**
    /**
@@ -351,8 +340,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
     */
     */
    private void verifyActivityCanHandleIntentAndExported(
    private void verifyActivityCanHandleIntentAndExported(
            Intent launchIntent, ComponentName component, int callingUid, @UserIdInt int userId) {
            Intent launchIntent, ComponentName component, int callingUid, @UserIdInt int userId) {
        final long ident = mInjector.clearCallingIdentity();
        mInjector.withCleanCallingIdentity(() -> {
        try {
            final List<ResolveInfo> apps =
            final List<ResolveInfo> apps =
                    mInjector.getPackageManagerInternal().queryIntentActivities(
                    mInjector.getPackageManagerInternal().queryIntentActivities(
                            launchIntent,
                            launchIntent,
@@ -371,9 +359,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
            }
            }
            throw new SecurityException("Attempt to launch activity without "
            throw new SecurityException("Attempt to launch activity without "
                    + " category Intent.CATEGORY_LAUNCHER or activity is not exported" + component);
                    + " category Intent.CATEGORY_LAUNCHER or activity is not exported" + component);
        } finally {
        });
            mInjector.restoreCallingIdentity(ident);
        }
    }
    }


    @Override
    @Override
@@ -385,7 +371,13 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
                    "INTERACT_ACROSS_USERS or INTERACT_ACROSS_USERS_FULL is required to set the"
                    "INTERACT_ACROSS_USERS or INTERACT_ACROSS_USERS_FULL is required to set the"
                            + " app-op for interacting across profiles.");
                            + " app-op for interacting across profiles.");
        }
        }
        final int callingUserId = mInjector.getCallingUserId();
        if (!isPermissionGranted(Manifest.permission.MANAGE_APP_OPS_MODES, callingUid)
                && !isPermissionGranted(
                        Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES, callingUid)) {
            throw new SecurityException(
                    "MANAGE_APP_OPS_MODES or CONFIGURE_INTERACT_ACROSS_PROFILES is required to set"
                            + " the app-op for interacting across profiles.");
        }
        if (newMode == AppOpsManager.MODE_ALLOWED
        if (newMode == AppOpsManager.MODE_ALLOWED
                && !canConfigureInteractAcrossProfiles(packageName)) {
                && !canConfigureInteractAcrossProfiles(packageName)) {
            // The user should not be prompted for apps that cannot request to interact across
            // The user should not be prompted for apps that cannot request to interact across
@@ -395,7 +387,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
            return;
            return;
        }
        }
        final int[] profileIds =
        final int[] profileIds =
                mInjector.getUserManager().getProfileIds(callingUserId, /* enabledOnly= */ false);
                mInjector.getUserManager()
                        .getProfileIds(mInjector.getCallingUserId(), /* enabledOnly= */ false);
        for (int profileId : profileIds) {
        for (int profileId : profileIds) {
            if (!isPackageInstalled(packageName, profileId)) {
            if (!isPackageInstalled(packageName, profileId)) {
                continue;
                continue;
@@ -406,8 +399,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {


    private boolean isPackageInstalled(String packageName, @UserIdInt int userId) {
    private boolean isPackageInstalled(String packageName, @UserIdInt int userId) {
        final int callingUid = mInjector.getCallingUid();
        final int callingUid = mInjector.getCallingUid();
        final long identity = mInjector.clearCallingIdentity();
        return mInjector.withCleanCallingIdentity(() -> {
        try {
            final PackageInfo info =
            final PackageInfo info =
                    mInjector.getPackageManagerInternal()
                    mInjector.getPackageManagerInternal()
                            .getPackageInfo(
                            .getPackageInfo(
@@ -416,9 +408,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
                                    callingUid,
                                    callingUid,
                                    userId);
                                    userId);
            return info != null;
            return info != null;
        } finally {
        });
            mInjector.restoreCallingIdentity(identity);
        }
    }
    }


    private void setInteractAcrossProfilesAppOpForUser(
    private void setInteractAcrossProfilesAppOpForUser(
@@ -440,19 +430,31 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
                    + packageName + " on user ID " + userId);
                    + packageName + " on user ID " + userId);
            return;
            return;
        }
        }
        final int callingUid = mInjector.getCallingUid();
        if (isPermissionGranted(
                Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES, callingUid)) {
            // Clear calling identity since the CONFIGURE_INTERACT_ACROSS_PROFILES permission allows
            // this particular app-op to be modified without the broader app-op permissions.
            mInjector.withCleanCallingIdentity(() ->
                    mInjector.getAppOpsManager()
                    mInjector.getAppOpsManager()
                .setMode(OP_INTERACT_ACROSS_PROFILES,
                            .setMode(OP_INTERACT_ACROSS_PROFILES, uid, packageName, newMode));
                        uid,
        } else {
                        packageName,
            mInjector.getAppOpsManager()
                        newMode);
                    .setMode(OP_INTERACT_ACROSS_PROFILES, uid, packageName, newMode);
        }
        sendCanInteractAcrossProfilesChangedBroadcast(packageName, uid, UserHandle.of(userId));
        sendCanInteractAcrossProfilesChangedBroadcast(packageName, uid, UserHandle.of(userId));
    }
    }


    /**
     * Returns whether the given app-op mode is equivalent to the currently-set app-op of the given
     * package name and UID. Clears identity to avoid permission checks, so ensure the caller does
     * any necessary permission checks.
     */
    private boolean currentModeEquals(@Mode int otherMode, String packageName, int uid) {
    private boolean currentModeEquals(@Mode int otherMode, String packageName, int uid) {
        final String op =
        final String op =
                AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES);
                AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES);
        return otherMode ==
        return mInjector.withCleanCallingIdentity(() -> otherMode
                mInjector.getAppOpsManager().unsafeCheckOpNoThrow(op, uid, packageName);
                == mInjector.getAppOpsManager().unsafeCheckOpNoThrow(op, uid, packageName));
    }
    }


    private void sendCanInteractAcrossProfilesChangedBroadcast(
    private void sendCanInteractAcrossProfilesChangedBroadcast(
@@ -493,8 +495,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
    }
    }


    private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) {
    private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) {
        final long ident = mInjector.clearCallingIdentity();
        return mInjector.withCleanCallingIdentity(() -> {
        try {
            final int[] profileIds =
            final int[] profileIds =
                    mInjector.getUserManager().getProfileIds(userId, /* enabledOnly= */ false);
                    mInjector.getUserManager().getProfileIds(userId, /* enabledOnly= */ false);
            for (int profileId : profileIds) {
            for (int profileId : profileIds) {
@@ -502,10 +503,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
                    return true;
                    return true;
                }
                }
            }
            }
        } finally {
            mInjector.restoreCallingIdentity(ident);
        }
            return false;
            return false;
        });
    }
    }


    @Override
    @Override
@@ -525,12 +524,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
    }
    }


    private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
    private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
        final long ident = mInjector.clearCallingIdentity();
        return mInjector.withCleanCallingIdentity(() ->
        try {
                mInjector.getUserManager().isSameProfileGroup(callerUserId, userId));
            return mInjector.getUserManager().isSameProfileGroup(callerUserId, userId);
        } finally {
            mInjector.restoreCallingIdentity(ident);
        }
    }
    }


    /**
    /**
@@ -560,42 +555,62 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
            mContext = context;
            mContext = context;
        }
        }


        @Override
        public int getCallingUid() {
        public int getCallingUid() {
            return Binder.getCallingUid();
            return Binder.getCallingUid();
        }
        }


        @Override
        public int getCallingPid() {
        public int getCallingPid() {
            return Binder.getCallingPid();
            return Binder.getCallingPid();
        }
        }


        @Override
        public int getCallingUserId() {
        public int getCallingUserId() {
            return UserHandle.getCallingUserId();
            return UserHandle.getCallingUserId();
        }
        }


        @Override
        public UserHandle getCallingUserHandle() {
        public UserHandle getCallingUserHandle() {
            return Binder.getCallingUserHandle();
            return Binder.getCallingUserHandle();
        }
        }


        @Override
        public long clearCallingIdentity() {
        public long clearCallingIdentity() {
            return Binder.clearCallingIdentity();
            return Binder.clearCallingIdentity();
        }
        }


        @Override
        public void restoreCallingIdentity(long token) {
        public void restoreCallingIdentity(long token) {
            Binder.restoreCallingIdentity(token);
            Binder.restoreCallingIdentity(token);
        }
        }


        @Override
        public void withCleanCallingIdentity(ThrowingRunnable action) {
            Binder.withCleanCallingIdentity(action);
        }

        @Override
        public final <T> T withCleanCallingIdentity(ThrowingSupplier<T> action) {
            return Binder.withCleanCallingIdentity(action);
        }

        @Override
        public UserManager getUserManager() {
        public UserManager getUserManager() {
            return mContext.getSystemService(UserManager.class);
            return mContext.getSystemService(UserManager.class);
        }
        }


        @Override
        public PackageManagerInternal getPackageManagerInternal() {
        public PackageManagerInternal getPackageManagerInternal() {
            return LocalServices.getService(PackageManagerInternal.class);
            return LocalServices.getService(PackageManagerInternal.class);
        }
        }


        @Override
        public PackageManager getPackageManager() {
        public PackageManager getPackageManager() {
            return mContext.getPackageManager();
            return mContext.getPackageManager();
        }
        }


        @Override
        public AppOpsManager getAppOpsManager() {
        public AppOpsManager getAppOpsManager() {
            return mContext.getSystemService(AppOpsManager.class);
            return mContext.getSystemService(AppOpsManager.class);
        }
        }
@@ -646,6 +661,10 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {


        void restoreCallingIdentity(long token);
        void restoreCallingIdentity(long token);


        void withCleanCallingIdentity(ThrowingRunnable action);

        <T> T withCleanCallingIdentity(ThrowingSupplier<T> action);

        UserManager getUserManager();
        UserManager getUserManager();


        PackageManagerInternal getPackageManagerInternal();
        PackageManagerInternal getPackageManagerInternal();
+64 −2
Original line number Original line Diff line number Diff line
@@ -55,6 +55,8 @@ import android.platform.test.annotations.Presubmit;


import androidx.test.core.app.ApplicationProvider;
import androidx.test.core.app.ApplicationProvider;


import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
import com.android.server.LocalServices;
import com.android.server.LocalServices;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowUserManager;
import com.android.server.testing.shadows.ShadowUserManager;
@@ -190,6 +192,8 @@ public class CrossProfileAppsServiceImplRoboTest {
    public void grantPermissions() {
    public void grantPermissions() {
        grantPermissions(
        grantPermissions(
                Manifest.permission.MANAGE_APP_OPS_MODES,
                Manifest.permission.MANAGE_APP_OPS_MODES,
                Manifest.permission.UPDATE_APP_OPS_STATS,
                Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
                Manifest.permission.INTERACT_ACROSS_USERS,
                Manifest.permission.INTERACT_ACROSS_USERS,
                Manifest.permission.INTERACT_ACROSS_USERS_FULL);
                Manifest.permission.INTERACT_ACROSS_USERS_FULL);
    }
    }
@@ -212,10 +216,27 @@ public class CrossProfileAppsServiceImplRoboTest {
        explicitlySetInteractAcrossProfilesAppOp(WORK_PROFILE_UID, defaultMode);
        explicitlySetInteractAcrossProfilesAppOp(WORK_PROFILE_UID, defaultMode);
    }
    }


    @Test
    public void setInteractAcrossProfilesAppOp_noPermissions_throwsSecurityException() {
        denyPermissions(
                Manifest.permission.MANAGE_APP_OPS_MODES,
                Manifest.permission.UPDATE_APP_OPS_STATS,
                Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
                Manifest.permission.INTERACT_ACROSS_USERS,
                Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        try {
            mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
                    CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
            fail();
        } catch (SecurityException expected) {}
    }

    @Test
    @Test
    public void setInteractAcrossProfilesAppOp_missingInteractAcrossUsersAndFull_throwsSecurityException() {
    public void setInteractAcrossProfilesAppOp_missingInteractAcrossUsersAndFull_throwsSecurityException() {
        denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS);
        denyPermissions(
        denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
                Manifest.permission.INTERACT_ACROSS_USERS,
                Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        grantPermissions(Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES);
        try {
        try {
            mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
            mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
                    CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
                    CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
@@ -230,9 +251,39 @@ public class CrossProfileAppsServiceImplRoboTest {
        assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
        assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
    }
    }


    @Test
    public void setInteractAcrossProfilesAppOp_configureInteractAcrossProfilesPermissionWithoutAppOpsPermissions_setsAppOp() {
        denyPermissions(
                Manifest.permission.MANAGE_APP_OPS_MODES,
                Manifest.permission.UPDATE_APP_OPS_STATS);
        grantPermissions(
                Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
                Manifest.permission.INTERACT_ACROSS_USERS);

        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
                CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);

        assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
    }

    @Test
    public void setInteractAcrossProfilesAppOp_appOpsPermissionsWithoutConfigureInteractAcrossProfilesPermission_setsAppOp() {
        denyPermissions(Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES);
        grantPermissions(
                Manifest.permission.MANAGE_APP_OPS_MODES,
                Manifest.permission.UPDATE_APP_OPS_STATS,
                Manifest.permission.INTERACT_ACROSS_USERS);

        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
                CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);

        assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
    }

    @Test
    @Test
    public void setInteractAcrossProfilesAppOp_setsAppOpWithUsersAndWithoutFull() {
    public void setInteractAcrossProfilesAppOp_setsAppOpWithUsersAndWithoutFull() {
        denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        grantPermissions(Manifest.permission.INTERACT_ACROSS_USERS);
        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
                CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
                CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
        assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
        assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
@@ -241,6 +292,7 @@ public class CrossProfileAppsServiceImplRoboTest {
    @Test
    @Test
    public void setInteractAcrossProfilesAppOp_setsAppOpWithFullAndWithoutUsers() {
    public void setInteractAcrossProfilesAppOp_setsAppOpWithFullAndWithoutUsers() {
        denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS);
        denyPermissions(Manifest.permission.INTERACT_ACROSS_USERS);
        grantPermissions(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
        mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
                CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
                CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
        assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
        assertThat(getCrossProfileAppOp()).isEqualTo(MODE_ALLOWED);
@@ -478,6 +530,16 @@ public class CrossProfileAppsServiceImplRoboTest {
        @Override
        @Override
        public void restoreCallingIdentity(long token) {}
        public void restoreCallingIdentity(long token) {}


        @Override
        public void withCleanCallingIdentity(ThrowingRunnable action) {
            action.run();
        }

        @Override
        public <T> T withCleanCallingIdentity(ThrowingSupplier<T> action) {
            return action.get();
        }

        @Override
        @Override
        public UserManager getUserManager() {
        public UserManager getUserManager() {
            return mUserManager;
            return mUserManager;
Loading