From 1831723eec87062636f7edaff41f1b930ff610e4 Mon Sep 17 00:00:00 2001 From: Ilyas Sung Date: Mon, 27 Feb 2023 16:48:42 +0000 Subject: [PATCH] Allows affiliated profile owners to start activities in the background Bug: 268159214 Test: atest ActivityManagerServiceTest atest com.android.server.wm.ActivityStarterTests Change-Id: I7910eda863a8b6f3678ab708e1f4bcf55fb0bd05 --- .../android/app/admin/DeviceStateCache.java | 8 +++ .../wm/ActivityTaskManagerInternal.java | 5 ++ .../server/wm/ActivityTaskManagerService.java | 19 ++++++ .../wm/BackgroundActivityStartController.java | 8 +++ .../DevicePolicyManagerService.java | 18 +++++- .../devicepolicy/DeviceStateCacheImpl.java | 15 +++++ .../android/server/devicepolicy/Owners.java | 24 ++++++-- .../server/wm/ActivityStarterTests.java | 58 +++++++++++++------ 8 files changed, 130 insertions(+), 25 deletions(-) diff --git a/core/java/android/app/admin/DeviceStateCache.java b/core/java/android/app/admin/DeviceStateCache.java index d1d130d88a39d..f37f5411be2c9 100644 --- a/core/java/android/app/admin/DeviceStateCache.java +++ b/core/java/android/app/admin/DeviceStateCache.java @@ -49,6 +49,14 @@ public abstract class DeviceStateCache { */ public abstract boolean isUserOrganizationManaged(@UserIdInt int userHandle); + /** + * Returns whether a user has affiliated IDs. + */ + + public boolean hasAffiliationWithDevice(int userId) { + return false; + } + /** * Empty implementation. */ diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 7926216fe15d6..9f738ed3fac19 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -584,6 +584,11 @@ public abstract class ActivityTaskManagerInternal { */ public abstract void setDeviceOwnerUid(int uid); + /** + * Called by DevicePolicyManagerService to set the uids of the profile owners. + */ + public abstract void setProfileOwnerUids(Set uids); + /** * Set all associated companion app that belongs to a userId. * @param userId diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index f35343c987117..48569f601c238 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -158,6 +158,7 @@ import android.app.PictureInPictureUiState; import android.app.ProfilerInfo; import android.app.WaitResult; import android.app.admin.DevicePolicyCache; +import android.app.admin.DeviceStateCache; import android.app.assist.ActivityId; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; @@ -783,6 +784,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private int mDeviceOwnerUid = Process.INVALID_UID; + private Set mProfileOwnerUids = new ArraySet(); + private final class SettingObserver extends ContentObserver { private final Uri mFontScaleUri = Settings.System.getUriFor(FONT_SCALE); private final Uri mHideErrorDialogsUri = Settings.Global.getUriFor(HIDE_ERROR_DIALOGS); @@ -5360,6 +5363,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mDeviceOwnerUid = uid; } + boolean isAffiliatedProfileOwner(int uid) { + return uid >= 0 && mProfileOwnerUids.contains(uid) + && DeviceStateCache.getInstance().hasAffiliationWithDevice(UserHandle.getUserId(uid)); + } + + void setProfileOwnerUids(Set uids) { + mProfileOwnerUids = uids; + } + /** * Saves the current activity manager state and includes the saved state in the next dump of * activity manager. @@ -6915,6 +6927,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } + @Override + public void setProfileOwnerUids(Set uids) { + synchronized (mGlobalLock) { + ActivityTaskManagerService.this.setProfileOwnerUids(uids); + } + } + @Override public void setCompanionAppUids(int userId, Set companionAppUids) { synchronized (mGlobalLock) { diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index 1a3d6730fe203..dc49e8cea18b9 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -342,6 +342,14 @@ public class BackgroundActivityStartController { /*background*/ true, callingUid, realCallingUid, intent, "Device Owner"); } + // don't abort if the callingUid is a affiliated profile owner + if (mService.isAffiliatedProfileOwner(callingUid)) { + return logStartAllowedAndReturnCode( + BAL_ALLOW_ALLOWLISTED_COMPONENT, + resultIfPiSenderAllowsBal, balAllowedByPiSender, + /*background*/ true, callingUid, realCallingUid, + intent, "Affiliated Profile Owner"); + } // don't abort if the callingUid has companion device final int callingUserId = UserHandle.getUserId(callingUid); if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 187e51ad9cf6a..9d1c77d10403e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -10329,6 +10329,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mSecondaryLockscreenEnabled = false; policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED; policy.mAffiliationIds.clear(); + resetAffiliationCacheLocked(); policy.mLockTaskPackages.clear(); if (!isPolicyEngineForFinanceFlagEnabled()) { updateLockTaskPackagesLocked(mContext, policy.mLockTaskPackages, userId); @@ -18022,10 +18023,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (getLockObject()) { getUserData(callingUserId).mAffiliationIds = affiliationIds; saveSettingsLocked(callingUserId); - if (callingUserId != UserHandle.USER_SYSTEM && isDeviceOwner(admin, callingUserId)) { + mStateCache.setHasAffiliationWithDevice(callingUserId, + isUserAffiliatedWithDeviceLocked(callingUserId)); + if (callingUserId == UserHandle.USER_SYSTEM) { + resetAffiliationCacheLocked(); + } else if (callingUserId != UserHandle.USER_SYSTEM && isDeviceOwner(admin, + callingUserId)) { // Affiliation ids specified by the device owner are additionally stored in // UserHandle.USER_SYSTEM's DevicePolicyData. getUserData(UserHandle.USER_SYSTEM).mAffiliationIds = affiliationIds; + mStateCache.setHasAffiliationWithDevice(UserHandle.USER_SYSTEM, true); saveSettingsLocked(UserHandle.USER_SYSTEM); } @@ -18039,6 +18046,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private void resetAffiliationCacheLocked() { + mInjector.binderWithCleanCallingIdentity(() -> { + for (UserInfo user : mUserManager.getUsers()) { + mStateCache.setHasAffiliationWithDevice(user.id, + isUserAffiliatedWithDeviceLocked(user.id)); + } + }); + } + @Override public List getAffiliationIds(ComponentName admin) { if (!mHasFeature) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java index 011a282ead7a0..47607d7426e88 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java @@ -42,6 +42,8 @@ public class DeviceStateCacheImpl extends DeviceStateCache { private AtomicInteger mDeviceOwnerType = new AtomicInteger(NO_DEVICE_OWNER); private Map mHasProfileOwner = new ConcurrentHashMap<>(); + private Map mAffiliationWithDevice = new ConcurrentHashMap<>(); + @GuardedBy("mLock") private boolean mIsDeviceProvisioned = false; @@ -70,6 +72,19 @@ public class DeviceStateCacheImpl extends DeviceStateCache { } } + void setHasAffiliationWithDevice(int userId, Boolean hasAffiliateProfileOwner) { + if (hasAffiliateProfileOwner) { + mAffiliationWithDevice.put(userId, true); + } else { + mAffiliationWithDevice.remove(userId); + } + } + + @Override + public boolean hasAffiliationWithDevice(int userId) { + return mAffiliationWithDevice.getOrDefault(userId, false); + } + @Override public boolean isUserOrganizationManaged(@UserIdInt int userHandle) { if (mHasProfileOwner.getOrDefault(userHandle, false) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java index 194647fda92c5..0c1c406dd7e2d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java @@ -131,7 +131,8 @@ class Owners { } notifyChangeLocked(); - pushToActivityTaskManagerLocked(); + pushDeviceOwnerUidToActivityTaskManagerLocked(); + pushProfileOwnerUidsToActivityTaskManagerLocked(); } } @@ -163,10 +164,15 @@ class Owners { } @GuardedBy("mData") - private void pushToActivityTaskManagerLocked() { + private void pushDeviceOwnerUidToActivityTaskManagerLocked() { mActivityTaskManagerInternal.setDeviceOwnerUid(getDeviceOwnerUidLocked()); } + @GuardedBy("mData") + private void pushProfileOwnerUidsToActivityTaskManagerLocked() { + mActivityTaskManagerInternal.setProfileOwnerUids(getProfileOwnerUidsLocked()); + } + @GuardedBy("mData") private void pushToActivityManagerLocked() { mActivityManagerInternal.setDeviceOwnerUid(getDeviceOwnerUidLocked()); @@ -196,6 +202,11 @@ class Owners { } } + @GuardedBy("mData") + Set getProfileOwnerUidsLocked() { + return mData.mProfileOwners.keySet(); + } + String getDeviceOwnerPackageName() { synchronized (mData) { return mData.mDeviceOwner != null ? mData.mDeviceOwner.packageName : null; @@ -263,7 +274,7 @@ class Owners { } notifyChangeLocked(); - pushToActivityTaskManagerLocked(); + pushDeviceOwnerUidToActivityTaskManagerLocked(); } } @@ -282,7 +293,7 @@ class Owners { mUserManagerInternal.setDeviceManaged(false); } notifyChangeLocked(); - pushToActivityTaskManagerLocked(); + pushDeviceOwnerUidToActivityTaskManagerLocked(); } } @@ -302,6 +313,7 @@ class Owners { mUserManagerInternal.setUserManaged(userId, true); } notifyChangeLocked(); + pushProfileOwnerUidsToActivityTaskManagerLocked(); } } @@ -317,6 +329,7 @@ class Owners { mUserManagerInternal.setUserManaged(userId, false); } notifyChangeLocked(); + pushProfileOwnerUidsToActivityTaskManagerLocked(); } } @@ -328,6 +341,7 @@ class Owners { ownerInfo.isOrganizationOwnedDevice); mData.mProfileOwners.put(userId, newOwnerInfo); notifyChangeLocked(); + pushProfileOwnerUidsToActivityTaskManagerLocked(); } } @@ -345,7 +359,7 @@ class Owners { mData.mDeviceOwner.packageName, previousDeviceOwnerType); } notifyChangeLocked(); - pushToActivityTaskManagerLocked(); + pushDeviceOwnerUidToActivityTaskManagerLocked(); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 95fc0faf50ba9..2671e771aa598 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -645,7 +645,7 @@ public class ActivityStarterTests extends WindowTestsBase { runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false); + false, false, false, false, false, false, false, false); } /** @@ -659,7 +659,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_unsupportedUsecase_aborted", true, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false); + false, false, false, false, false, false, false, false); } /** @@ -673,7 +673,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_callingUidProcessStateTop_aborted", true, UNIMPORTANT_UID, false, PROCESS_STATE_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false); + false, false, false, false, false, false, false, false); } /** @@ -687,7 +687,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_realCallingUidProcessStateTop_aborted", true, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, - false, false, false, false, false, false, false); + false, false, false, false, false, false, false, false); } /** @@ -701,7 +701,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_hasForegroundActivities_aborted", true, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - true, false, false, false, false, false, false); + true, false, false, false, false, false, false, false); } /** @@ -715,7 +715,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_pinned_singleinstance_aborted", true, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, true, false); + false, false, false, false, false, false, true, false); } /** @@ -729,7 +729,7 @@ public class ActivityStarterTests extends WindowTestsBase { runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false, Process.ROOT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false); + false, false, false, false, false, false, false, false); } /** @@ -743,7 +743,7 @@ public class ActivityStarterTests extends WindowTestsBase { runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false, Process.SYSTEM_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false); + false, false, false, false, false, false, false, false); } /** @@ -757,7 +757,7 @@ public class ActivityStarterTests extends WindowTestsBase { runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false, Process.NFC_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false); + false, false, false, false, false, false, false, false); } /** @@ -772,7 +772,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_callingUidHasVisibleWindow_notAborted", false, UNIMPORTANT_UID, true, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false); + false, false, false, false, false, false, false, false); } /** @@ -788,7 +788,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_realCallingUidHasVisibleWindow_abortedInU", true, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, true, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false); + false, false, false, false, false, false, false, false); } /** @@ -803,7 +803,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_callerIsRecents_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false); + false, true, false, false, false, false, false, false); } /** @@ -818,7 +818,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_callerIsAllowed_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, true, false, false, false, false); + false, false, true, false, false, false, false, false); } /** @@ -834,7 +834,7 @@ public class ActivityStarterTests extends WindowTestsBase { false, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, true, false, false, false); + false, false, false, true, false, false, false, false); } /** @@ -850,7 +850,23 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_callingPackageNameIsDeviceOwner_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, true, false, false); + false, false, false, false, true, false, false, false); + } + + /** + * This test ensures that supported usecases aren't aborted when background starts are + * disallowed. Each scenarios tests one condition that makes them supported in isolation. In + * this case the caller is a affiliated profile owner. + */ + @Test + public void + testBackgroundActivityStartsDisallowed_isAffiliatedProfileOwnerNotAborted() { + doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_callingUidIsAffiliatedProfileOwner_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, + UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, + false, false, false, false, false, true, false, false); } /** @@ -865,7 +881,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_callerHasSystemExemptAppOpNotAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, true); + false, false, false, false, false, false, false, true); } /** @@ -881,7 +897,7 @@ public class ActivityStarterTests extends WindowTestsBase { "disallowed_callingPackageNameIsIme_notAborted", false, CURRENT_IME_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, false, false, false, false, false, false); + false, false, false, false, false, false, false, false); } /** @@ -902,7 +918,7 @@ public class ActivityStarterTests extends WindowTestsBase { "allowed_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false); + false, true, false, false, false, false, false, false); verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, "", // activity name BackgroundActivityStartController.BAL_ALLOW_PERMISSION, @@ -933,7 +949,7 @@ public class ActivityStarterTests extends WindowTestsBase { "allowed_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, - false, true, false, false, false, false, false); + false, true, false, false, false, false, false, false); verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME, BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT, @@ -949,6 +965,7 @@ public class ActivityStarterTests extends WindowTestsBase { boolean callerIsTempAllowed, boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, boolean isCallingUidDeviceOwner, + boolean isCallingUidAffiliatedProfileOwner, boolean isPinnedSingleInstance, boolean hasSystemExemptAppOp) { // window visibility @@ -982,6 +999,9 @@ public class ActivityStarterTests extends WindowTestsBase { callerIsInstrumentingWithBackgroundActivityStartPrivileges); // callingUid is the device owner doReturn(isCallingUidDeviceOwner).when(mAtm).isDeviceOwner(callingUid); + // callingUid is the affiliated profile owner + doReturn(isCallingUidAffiliatedProfileOwner).when(mAtm) + .isAffiliatedProfileOwner(callingUid); // caller has OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop doReturn(hasSystemExemptAppOp ? AppOpsManager.MODE_ALLOWED