1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.bedstead.enterprise 17 18 import com.android.bedstead.accounts.AccountsComponent 19 import com.android.bedstead.enterprise.annotations.EnsureHasNoProfileOwner 20 import com.android.bedstead.enterprise.annotations.EnsureHasProfileOwner 21 import com.android.bedstead.harrier.BedsteadServiceLocator 22 import com.android.bedstead.harrier.DeviceState 23 import com.android.bedstead.harrier.DeviceStateComponent 24 import com.android.bedstead.harrier.UserType 25 import com.android.bedstead.harrier.annotations.EnsureTestAppInstalled 26 import com.android.bedstead.harrier.annotations.FailureMode 27 import com.android.bedstead.harrier.components.UserTypeResolver 28 import com.android.bedstead.nene.TestApis.devicePolicy 29 import com.android.bedstead.nene.devicepolicy.DevicePolicyController 30 import com.android.bedstead.nene.userrestrictions.CommonUserRestrictions 31 import com.android.bedstead.nene.users.UserReference 32 import com.android.bedstead.nene.utils.Versions 33 import com.android.bedstead.remotedpc.RemoteDpc 34 import com.android.bedstead.remotedpc.RemoteDpcUsingParentInstance 35 import com.android.bedstead.testapp.TestApp 36 import com.android.bedstead.testapp.TestAppProvider 37 import com.android.bedstead.testapp.TestAppQueryBuilder 38 import com.android.bedstead.testapps.TestAppsComponent 39 40 /** 41 * Manages profile owners for device state tests. 42 * 43 * @param locator provides access to other dependencies. 44 */ 45 class ProfileOwnersComponent(locator: BedsteadServiceLocator) : DeviceStateComponent { 46 47 private val userTypeResolver: UserTypeResolver by locator 48 private val deviceOwnerComponent: DeviceOwnerComponent by locator 49 private val enterpriseComponent: EnterpriseComponent by locator 50 private val testAppsComponent: TestAppsComponent by locator 51 private val userRestrictionsComponent: UserRestrictionsComponent by locator 52 private val accountsComponent: AccountsComponent by locator 53 private val profileOwners: MutableMap<UserReference, DevicePolicyController?> = HashMap() 54 private val changedProfileOwners: MutableMap<UserReference, DevicePolicyController?> = HashMap() 55 56 /** 57 * Gets the existing profile owner instance for the given [user]. 58 */ 59 fun getExistingProfileOwner(user: UserReference) = profileOwners[user] 60 61 /** 62 * See [EnsureHasNoProfileOwner] 63 */ 64 fun ensureHasNoProfileOwner(userType: UserType) { 65 ensureHasNoProfileOwner(userTypeResolver.toUser(userType)) 66 } 67 68 /** 69 * See [EnsureHasProfileOwner] 70 */ 71 fun ensureHasProfileOwner(annotation: EnsureHasProfileOwner) { 72 // TODO(scottjonathan): Should support non-remotedpc profile owner 73 // (default to remotedpc) 74 annotation.apply { 75 val user: UserReference = userTypeResolver.toUser(onUser) 76 ensureHasProfileOwner( 77 user, 78 isPrimary, 79 useParentInstance, 80 affiliationIds.toSet(), 81 key, 82 TestAppProvider().query(dpc) 83 ) 84 } 85 } 86 87 /** 88 * See [EnsureHasProfileOwner] 89 */ 90 fun ensureHasProfileOwner( 91 user: UserReference, 92 isPrimary: Boolean = false, 93 useParentInstance: Boolean = false, 94 affiliationIds: Set<String>? = emptySet(), 95 key: String? = EnsureTestAppInstalled.DEFAULT_KEY, 96 dpcQuery: TestAppQueryBuilder = TestAppProvider().query(), 97 resolvedDpcTestApp: TestApp? = null 98 ) { 99 var dpcQueryMutable = dpcQuery 100 dpcQueryMutable.applyAnnotation( 101 testAppsComponent.additionalQueryParameters.getOrDefault(key, null) 102 ) 103 if (dpcQueryMutable.isEmptyQuery) { 104 dpcQueryMutable = TestAppProvider() 105 .query() 106 .wherePackageName() 107 .isEqualTo(RemoteDpc.REMOTE_DPC_APP_PACKAGE_NAME_OR_PREFIX) 108 } 109 check( 110 !isPrimary || enterpriseComponent.primaryPolicyManager == null || 111 user == enterpriseComponent.primaryPolicyManager?.user() 112 ) { "Only one DPC can be marked as primary per test" } 113 val currentProfileOwner = devicePolicy().getProfileOwner(user) 114 val currentDeviceOwner = devicePolicy().getDeviceOwner() 115 if (currentDeviceOwner != null && currentDeviceOwner.user() == user) { 116 // Can't have DO and PO on the same user 117 deviceOwnerComponent.ensureHasNoDeviceOwner() 118 } 119 if (RemoteDpc.matchesRemoteDpcQuery(currentProfileOwner, dpcQueryMutable)) { 120 profileOwners[user] = currentProfileOwner 121 } else { 122 if (user.parent() != null) { 123 userRestrictionsComponent.ensureDoesNotHaveUserRestriction( 124 CommonUserRestrictions.DISALLOW_ADD_MANAGED_PROFILE, 125 user.parent() 126 ) 127 } 128 if (!changedProfileOwners.containsKey(user)) { 129 changedProfileOwners[user] = currentProfileOwner 130 } 131 accountsComponent.ensureHasNoAccounts( 132 user, 133 allowPreCreatedAccounts = true, 134 FailureMode.FAIL 135 ) 136 if (resolvedDpcTestApp != null) { 137 profileOwners[user] = 138 RemoteDpc.setAsProfileOwner(user, resolvedDpcTestApp) 139 .devicePolicyController() 140 } else { 141 profileOwners[user] = 142 RemoteDpc.setAsProfileOwner(user, dpcQueryMutable).devicePolicyController() 143 } 144 } 145 if (Versions.meetsMinimumSdkVersionRequirement(Versions.U)) { 146 accountsComponent.ensureHasNoAccounts( 147 user, 148 allowPreCreatedAccounts = true, 149 FailureMode.FAIL 150 ) 151 } else { 152 // Prior to U this incorrectly checked the system user 153 accountsComponent.ensureHasNoAccounts( 154 UserType.SYSTEM_USER, 155 allowPreCreatedAccounts = true, 156 FailureMode.FAIL 157 ) 158 } 159 if (isPrimary) { 160 enterpriseComponent.primaryPolicyManager = if (useParentInstance) { 161 RemoteDpcUsingParentInstance( 162 RemoteDpc.forDevicePolicyController(profileOwners[user]) 163 ) 164 } else { 165 RemoteDpc.forDevicePolicyController(profileOwners[user]) 166 } 167 } 168 if (affiliationIds != null) { 169 val profileOwner: RemoteDpc = profileOwner(user) 170 profileOwner.devicePolicyManager() 171 .setAffiliationIds(profileOwner.componentName(), affiliationIds) 172 } 173 } 174 175 /** 176 * Removes existing profile owner on the device for the specified [user] 177 */ 178 fun ensureHasNoProfileOwner(user: UserReference) { 179 val currentProfileOwner = devicePolicy().getProfileOwner(user) ?: return 180 if (!changedProfileOwners.containsKey(user)) { 181 changedProfileOwners[user] = currentProfileOwner 182 } 183 devicePolicy().getProfileOwner(user)!!.remove() 184 profileOwners.remove(user) 185 } 186 187 override fun teardownShareableState() { 188 changedProfileOwners.forEach { (key, value) -> 189 val currentProfileOwner = devicePolicy().getProfileOwner(key) 190 if (currentProfileOwner != value) { 191 currentProfileOwner?.remove() 192 if (value != null) { 193 devicePolicy().setProfileOwner(key, value.componentName()) 194 } 195 } 196 } 197 changedProfileOwners.clear() 198 } 199 200 /** 201 * See [DeviceState.profileOwner] 202 */ 203 fun profileOwner(): RemoteDpc { 204 return profileOwner(UserType.INSTRUMENTED_USER) 205 } 206 207 /** 208 * See [DeviceState.profileOwner] 209 */ 210 fun profileOwner(onUser: UserType): RemoteDpc { 211 return profileOwner(userTypeResolver.toUser(onUser)) 212 } 213 214 /** 215 * See [DeviceState.profileOwner] 216 */ 217 fun profileOwner(onUser: UserReference): RemoteDpc { 218 check(profileOwners.containsKey(onUser)) { 219 ("No Harrier-managed profile owner. This method should " + 220 "only be used when Harrier was used to set the Profile Owner.") 221 } 222 val profileOwner = profileOwners[onUser] 223 check(RemoteDpc.isRemoteDpc(profileOwner)) { 224 ("The profile owner is not a RemoteDPC." + 225 " You must use Nene to query for this profile owner.") 226 } 227 return RemoteDpc.forDevicePolicyController(profileOwner) 228 } 229 } 230