Loading core/java/android/content/pm/CrossProfileApps.java +28 −0 Original line number Original line Diff line number Diff line Loading @@ -487,6 +487,34 @@ public class CrossProfileApps { } } } } /** * Clears the app-op for {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} back to * its default value for every package on the device. * * <p>This method can be used to ensure that app-op state is not left around on existing users * for previously-configured profiles. * * <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 */ @RequiresPermission( allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void clearInteractAcrossProfilesAppOps() { try { mService.clearInteractAcrossProfilesAppOps(); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } private void verifyCanAccessUser(UserHandle userHandle) { private void verifyCanAccessUser(UserHandle userHandle) { if (!getTargetUserProfiles().contains(userHandle)) { if (!getTargetUserProfiles().contains(userHandle)) { throw new SecurityException("Not allowed to access " + userHandle); throw new SecurityException("Not allowed to access " + userHandle); Loading core/java/android/content/pm/ICrossProfileApps.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -40,4 +40,5 @@ interface ICrossProfileApps { boolean canConfigureInteractAcrossProfiles(in String packageName); boolean canConfigureInteractAcrossProfiles(in String packageName); boolean canUserAttemptToConfigureInteractAcrossProfiles(in String packageName); boolean canUserAttemptToConfigureInteractAcrossProfiles(in String packageName); void resetInteractAcrossProfilesAppOps(in List<String> packageNames); void resetInteractAcrossProfilesAppOps(in List<String> packageNames); void clearInteractAcrossProfilesAppOps(); } } services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +20 −1 Original line number Original line Diff line number Diff line Loading @@ -64,6 +64,7 @@ import com.android.server.wm.ActivityTaskManagerInternal; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; import java.util.Objects; import java.util.Objects; import java.util.stream.Collectors; public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private static final String TAG = "CrossProfileAppsService"; private static final String TAG = "CrossProfileAppsService"; Loading Loading @@ -447,7 +448,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { final int uid = mInjector.getPackageManager() final int uid = mInjector.getPackageManager() .getPackageUidAsUser(packageName, /* flags= */ 0, userId); .getPackageUidAsUser(packageName, /* flags= */ 0, userId); if (currentModeEquals(newMode, packageName, uid)) { if (currentModeEquals(newMode, packageName, uid)) { Slog.w(TAG, "Attempt to set mode to existing value of " + newMode + " for " Slog.i(TAG, "Attempt to set mode to existing value of " + newMode + " for " + packageName + " on user ID " + userId); + packageName + " on user ID " + userId); return; return; } } Loading Loading @@ -577,6 +578,24 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { setInteractAcrossProfilesAppOp(packageName, AppOpsManager.opToDefaultMode(op)); setInteractAcrossProfilesAppOp(packageName, AppOpsManager.opToDefaultMode(op)); } } @Override public void clearInteractAcrossProfilesAppOps() { final int defaultMode = AppOpsManager.opToDefaultMode( AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES)); findAllPackageNames() .forEach(packageName -> setInteractAcrossProfilesAppOp(packageName, defaultMode)); } private List<String> findAllPackageNames() { return mInjector.getPackageManagerInternal() .getInstalledApplications( /* flags= */ 0, mInjector.getCallingUserId(), mInjector.getCallingUid()) .stream() .map(applicationInfo -> applicationInfo.packageName) .collect(Collectors.toList()); } CrossProfileAppsInternal getLocalService() { CrossProfileAppsInternal getLocalService() { return mLocalService; return mLocalService; } } Loading services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.pm; package com.android.server.pm; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES; import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES; import static android.content.Intent.FLAG_RECEIVER_FOREGROUND; import static android.content.Intent.FLAG_RECEIVER_FOREGROUND; import static android.content.Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND; import static android.content.Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND; Loading Loading @@ -104,6 +105,7 @@ public class CrossProfileAppsServiceImplRoboTest { private final CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl = private final CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl = new CrossProfileAppsServiceImpl(mContext, mInjector); new CrossProfileAppsServiceImpl(mContext, mInjector); private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>(); private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>(); private final Map<Integer, List<ApplicationInfo>> installedApplications = new HashMap<>(); @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private IPackageManager mIPackageManager; @Mock private IPackageManager mIPackageManager; Loading @@ -112,12 +114,18 @@ public class CrossProfileAppsServiceImplRoboTest { @Before @Before public void initializeMocks() throws Exception { public void initializeMocks() throws Exception { MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this); initializeInstalledApplicationsMock(); mockCrossProfileAppInstalledAndEnabledOnEachProfile(); mockCrossProfileAppInstalledAndEnabledOnEachProfile(); mockCrossProfileAppRequestsInteractAcrossProfiles(); mockCrossProfileAppRequestsInteractAcrossProfiles(); mockCrossProfileAppRegistersBroadcastReceiver(); mockCrossProfileAppRegistersBroadcastReceiver(); mockCrossProfileAppWhitelisted(); mockCrossProfileAppWhitelisted(); } } private void initializeInstalledApplicationsMock() { when(mPackageManagerInternal.getInstalledApplications(anyInt(), anyInt(), eq(CALLING_UID))) .thenAnswer(invocation -> installedApplications.get(invocation.getArgument(1))); } private void mockCrossProfileAppInstalledAndEnabledOnEachProfile() { private void mockCrossProfileAppInstalledAndEnabledOnEachProfile() { // They are enabled by default, so we simply have to ensure that a package info with an // They are enabled by default, so we simply have to ensure that a package info with an // application info is returned. // application info is returned. Loading @@ -138,11 +146,14 @@ public class CrossProfileAppsServiceImplRoboTest { when(mPackageManagerInternal.getPackage(uid)) when(mPackageManagerInternal.getPackage(uid)) .thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME) .thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME) .hideAsParsed()).hideAsFinal()); .hideAsParsed()).hideAsFinal()); installedApplications.putIfAbsent(userId, new ArrayList<>()); installedApplications.get(userId).add(packageInfo.applicationInfo); } } private PackageInfo buildTestPackageInfo() { private PackageInfo buildTestPackageInfo() { PackageInfo packageInfo = new PackageInfo(); PackageInfo packageInfo = new PackageInfo(); packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.packageName = CROSS_PROFILE_APP_PACKAGE_NAME; return packageInfo; return packageInfo; } } Loading Loading @@ -451,6 +462,13 @@ public class CrossProfileAppsServiceImplRoboTest { .isTrue(); .isTrue(); } } @Test public void clearInteractAcrossProfilesAppOps() { explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED); mCrossProfileAppsServiceImpl.clearInteractAcrossProfilesAppOps(); assertThat(getCrossProfileAppOp()).isEqualTo(MODE_DEFAULT); } private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) { private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) { explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode); explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode); } } Loading Loading
core/java/android/content/pm/CrossProfileApps.java +28 −0 Original line number Original line Diff line number Diff line Loading @@ -487,6 +487,34 @@ public class CrossProfileApps { } } } } /** * Clears the app-op for {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} back to * its default value for every package on the device. * * <p>This method can be used to ensure that app-op state is not left around on existing users * for previously-configured profiles. * * <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 */ @RequiresPermission( allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void clearInteractAcrossProfilesAppOps() { try { mService.clearInteractAcrossProfilesAppOps(); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } private void verifyCanAccessUser(UserHandle userHandle) { private void verifyCanAccessUser(UserHandle userHandle) { if (!getTargetUserProfiles().contains(userHandle)) { if (!getTargetUserProfiles().contains(userHandle)) { throw new SecurityException("Not allowed to access " + userHandle); throw new SecurityException("Not allowed to access " + userHandle); Loading
core/java/android/content/pm/ICrossProfileApps.aidl +1 −0 Original line number Original line Diff line number Diff line Loading @@ -40,4 +40,5 @@ interface ICrossProfileApps { boolean canConfigureInteractAcrossProfiles(in String packageName); boolean canConfigureInteractAcrossProfiles(in String packageName); boolean canUserAttemptToConfigureInteractAcrossProfiles(in String packageName); boolean canUserAttemptToConfigureInteractAcrossProfiles(in String packageName); void resetInteractAcrossProfilesAppOps(in List<String> packageNames); void resetInteractAcrossProfilesAppOps(in List<String> packageNames); void clearInteractAcrossProfilesAppOps(); } }
services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +20 −1 Original line number Original line Diff line number Diff line Loading @@ -64,6 +64,7 @@ import com.android.server.wm.ActivityTaskManagerInternal; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; import java.util.Objects; import java.util.Objects; import java.util.stream.Collectors; public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private static final String TAG = "CrossProfileAppsService"; private static final String TAG = "CrossProfileAppsService"; Loading Loading @@ -447,7 +448,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { final int uid = mInjector.getPackageManager() final int uid = mInjector.getPackageManager() .getPackageUidAsUser(packageName, /* flags= */ 0, userId); .getPackageUidAsUser(packageName, /* flags= */ 0, userId); if (currentModeEquals(newMode, packageName, uid)) { if (currentModeEquals(newMode, packageName, uid)) { Slog.w(TAG, "Attempt to set mode to existing value of " + newMode + " for " Slog.i(TAG, "Attempt to set mode to existing value of " + newMode + " for " + packageName + " on user ID " + userId); + packageName + " on user ID " + userId); return; return; } } Loading Loading @@ -577,6 +578,24 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { setInteractAcrossProfilesAppOp(packageName, AppOpsManager.opToDefaultMode(op)); setInteractAcrossProfilesAppOp(packageName, AppOpsManager.opToDefaultMode(op)); } } @Override public void clearInteractAcrossProfilesAppOps() { final int defaultMode = AppOpsManager.opToDefaultMode( AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES)); findAllPackageNames() .forEach(packageName -> setInteractAcrossProfilesAppOp(packageName, defaultMode)); } private List<String> findAllPackageNames() { return mInjector.getPackageManagerInternal() .getInstalledApplications( /* flags= */ 0, mInjector.getCallingUserId(), mInjector.getCallingUid()) .stream() .map(applicationInfo -> applicationInfo.packageName) .collect(Collectors.toList()); } CrossProfileAppsInternal getLocalService() { CrossProfileAppsInternal getLocalService() { return mLocalService; return mLocalService; } } Loading
services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.pm; package com.android.server.pm; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES; import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES; import static android.content.Intent.FLAG_RECEIVER_FOREGROUND; import static android.content.Intent.FLAG_RECEIVER_FOREGROUND; import static android.content.Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND; import static android.content.Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND; Loading Loading @@ -104,6 +105,7 @@ public class CrossProfileAppsServiceImplRoboTest { private final CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl = private final CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl = new CrossProfileAppsServiceImpl(mContext, mInjector); new CrossProfileAppsServiceImpl(mContext, mInjector); private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>(); private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>(); private final Map<Integer, List<ApplicationInfo>> installedApplications = new HashMap<>(); @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private IPackageManager mIPackageManager; @Mock private IPackageManager mIPackageManager; Loading @@ -112,12 +114,18 @@ public class CrossProfileAppsServiceImplRoboTest { @Before @Before public void initializeMocks() throws Exception { public void initializeMocks() throws Exception { MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this); initializeInstalledApplicationsMock(); mockCrossProfileAppInstalledAndEnabledOnEachProfile(); mockCrossProfileAppInstalledAndEnabledOnEachProfile(); mockCrossProfileAppRequestsInteractAcrossProfiles(); mockCrossProfileAppRequestsInteractAcrossProfiles(); mockCrossProfileAppRegistersBroadcastReceiver(); mockCrossProfileAppRegistersBroadcastReceiver(); mockCrossProfileAppWhitelisted(); mockCrossProfileAppWhitelisted(); } } private void initializeInstalledApplicationsMock() { when(mPackageManagerInternal.getInstalledApplications(anyInt(), anyInt(), eq(CALLING_UID))) .thenAnswer(invocation -> installedApplications.get(invocation.getArgument(1))); } private void mockCrossProfileAppInstalledAndEnabledOnEachProfile() { private void mockCrossProfileAppInstalledAndEnabledOnEachProfile() { // They are enabled by default, so we simply have to ensure that a package info with an // They are enabled by default, so we simply have to ensure that a package info with an // application info is returned. // application info is returned. Loading @@ -138,11 +146,14 @@ public class CrossProfileAppsServiceImplRoboTest { when(mPackageManagerInternal.getPackage(uid)) when(mPackageManagerInternal.getPackage(uid)) .thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME) .thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME) .hideAsParsed()).hideAsFinal()); .hideAsParsed()).hideAsFinal()); installedApplications.putIfAbsent(userId, new ArrayList<>()); installedApplications.get(userId).add(packageInfo.applicationInfo); } } private PackageInfo buildTestPackageInfo() { private PackageInfo buildTestPackageInfo() { PackageInfo packageInfo = new PackageInfo(); PackageInfo packageInfo = new PackageInfo(); packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.packageName = CROSS_PROFILE_APP_PACKAGE_NAME; return packageInfo; return packageInfo; } } Loading Loading @@ -451,6 +462,13 @@ public class CrossProfileAppsServiceImplRoboTest { .isTrue(); .isTrue(); } } @Test public void clearInteractAcrossProfilesAppOps() { explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED); mCrossProfileAppsServiceImpl.clearInteractAcrossProfilesAppOps(); assertThat(getCrossProfileAppOp()).isEqualTo(MODE_DEFAULT); } private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) { private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) { explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode); explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode); } } Loading