Kill app if cross profile app op gets revoked
Kill the app in both profiles if user/admin revokes
the cross profile app op permission, this is to ensure
that any cross profile bound services gets unbound as
soon as the app op is revoked.
Fixes: 154693902
Test: atest ManagedProfileCrossProfileTest
Test: atest FrameworksServicesTests:com.android.server.pm.CrossProfileAppsServiceImplTest
Test: atest CrossProfileAppsServiceImplRoboTest
Change-Id: Iaa3b9196468149c1cec51e9101989f1877374cc5
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 28c8642d..e82ee22 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -50,6 +50,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.permission.PermissionManager;
import android.stats.devicepolicy.DevicePolicyEnums;
import android.text.TextUtils;
import android.util.Slog;
@@ -458,6 +459,10 @@
+ packageName + " on user ID " + userId);
return;
}
+
+ final boolean hadPermission = hasInteractAcrossProfilesPermission(
+ packageName, uid, PermissionChecker.PID_UNKNOWN);
+
final int callingUid = mInjector.getCallingUid();
if (isPermissionGranted(
Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES, callingUid)) {
@@ -472,6 +477,22 @@
}
sendCanInteractAcrossProfilesChangedBroadcast(packageName, uid, UserHandle.of(userId));
maybeLogSetInteractAcrossProfilesAppOp(packageName, newMode, userId, logMetrics, uid);
+ maybeKillUid(packageName, uid, hadPermission);
+ }
+
+ /**
+ * Kills the process represented by the given UID if it has lost the permission to
+ * interact across profiles.
+ */
+ private void maybeKillUid(
+ String packageName, int uid, boolean hadPermission) {
+ if (!hadPermission) {
+ return;
+ }
+ if (hasInteractAcrossProfilesPermission(packageName, uid, PermissionChecker.PID_UNKNOWN)) {
+ return;
+ }
+ mInjector.killUid(packageName, uid);
}
private void maybeLogSetInteractAcrossProfilesAppOp(
@@ -774,6 +795,18 @@
String permission, int uid, int owningUid, boolean exported) {
return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
}
+
+ @Override
+ public void killUid(String packageName, int uid) {
+ try {
+ ActivityManager.getService().killApplication(
+ packageName,
+ UserHandle.getAppId(uid),
+ UserHandle.getUserId(uid),
+ PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED);
+ } catch (RemoteException ignored) {
+ }
+ }
}
@VisibleForTesting
@@ -813,6 +846,8 @@
void sendBroadcastAsUser(Intent intent, UserHandle user);
int checkComponentPermission(String permission, int uid, int owningUid, boolean exported);
+
+ void killUid(String packageName, int uid);
}
class LocalService extends CrossProfileAppsInternal {
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index f8d197a..d78dad5 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -46,6 +46,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.os.Process;
import android.os.UserHandle;
@@ -106,6 +107,7 @@
new CrossProfileAppsServiceImpl(mContext, mInjector);
private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>();
private final Map<Integer, List<ApplicationInfo>> installedApplications = new HashMap<>();
+ private final Set<Integer> mKilledUids = new HashSet<>();
@Mock private PackageManagerInternal mPackageManagerInternal;
@Mock private IPackageManager mIPackageManager;
@@ -389,6 +391,33 @@
}
@Test
+ public void setInteractAcrossProfilesAppOp_toAllowed_doesNotKillApp() {
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+ assertThat(mKilledUids).isEmpty();
+ }
+
+ @Test
+ public void setInteractAcrossProfilesAppOp_toDisallowed_killsAppsInBothProfiles() {
+ shadowOf(mPackageManager).addPermissionInfo(createCrossProfilesPermissionInfo());
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_ALLOWED);
+
+ mCrossProfileAppsServiceImpl.setInteractAcrossProfilesAppOp(
+ CROSS_PROFILE_APP_PACKAGE_NAME, MODE_DEFAULT);
+
+ assertThat(mKilledUids).contains(WORK_PROFILE_UID);
+ assertThat(mKilledUids).contains(PERSONAL_PROFILE_UID);
+ }
+
+ private PermissionInfo createCrossProfilesPermissionInfo() {
+ PermissionInfo permissionInfo = new PermissionInfo();
+ permissionInfo.name = Manifest.permission.INTERACT_ACROSS_PROFILES;
+ permissionInfo.protectionLevel = PermissionInfo.PROTECTION_FLAG_APPOP;
+ return permissionInfo;
+ }
+
+ @Test
public void canConfigureInteractAcrossProfiles_packageNotInstalledInProfile_returnsFalse() {
mockUninstallCrossProfileAppFromWorkProfile();
assertThat(mCrossProfileAppsServiceImpl
@@ -678,5 +707,10 @@
// ShadowActivityThread with Robolectric. This method is currently not supported there.
return mContext.checkPermission(permission, Process.myPid(), uid);
}
+
+ @Override
+ public void killUid(String packageName, int uid) {
+ mKilledUids.add(uid);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
index e79b5af..a2393a8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
@@ -32,8 +32,10 @@
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.permission.PermissionManager;
import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
@@ -692,5 +694,17 @@
String permission, int uid, int owningUid, boolean exported) {
return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported);
}
+
+ @Override
+ public void killUid(String packageName, int uid) {
+ try {
+ ActivityManager.getService().killApplication(
+ packageName,
+ UserHandle.getAppId(uid),
+ UserHandle.getUserId(uid),
+ PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED);
+ } catch (RemoteException ignored) {
+ }
+ }
}
}