1 /* 2 * 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 android.util.Log 19 import com.android.bedstead.accounts.AccountsComponent 20 import com.android.bedstead.enterprise.annotations.EnsureHasDelegate 21 import com.android.bedstead.enterprise.annotations.EnsureHasDevicePolicyManagerRoleHolder 22 import com.android.bedstead.enterprise.annotations.EnsureHasNoDelegate 23 import com.android.bedstead.enterprise.annotations.EnsureHasWorkProfile 24 import com.android.bedstead.enterprise.annotations.EnsureTestAppInstalledAsPrimaryDPC 25 import com.android.bedstead.enterprise.annotations.RequireRunOnWorkProfile 26 import com.android.bedstead.harrier.BedsteadServiceLocator 27 import com.android.bedstead.harrier.DeviceStateComponent 28 import com.android.bedstead.harrier.UserType 29 import com.android.bedstead.harrier.annotations.FailureMode 30 import com.android.bedstead.harrier.components.UserTypeResolver 31 import com.android.bedstead.multiuser.UsersComponent 32 import com.android.bedstead.nene.TestApis.devicePolicy 33 import com.android.bedstead.nene.TestApis.users 34 import com.android.bedstead.nene.devicepolicy.ProfileOwner 35 import com.android.bedstead.nene.users.UserReference 36 import com.android.bedstead.remotedpc.RemoteDelegate 37 import com.android.bedstead.remotedpc.RemoteDevicePolicyManagerRoleHolder 38 import com.android.bedstead.remotedpc.RemoteDpc 39 import com.android.bedstead.remotedpc.RemotePolicyManager 40 import com.android.bedstead.remotedpc.RemoteTestApp 41 import com.android.bedstead.testapp.TestAppInstance 42 import com.android.bedstead.testapp.TestAppProvider 43 import com.android.bedstead.testapps.TestAppsComponent 44 45 /** 46 * Contains Enterprise specific logic for device state tests. 47 * 48 * @param locator provides access to other dependencies. 49 */ 50 class EnterpriseComponent(locator: BedsteadServiceLocator) : DeviceStateComponent { 51 52 private val deviceOwnerComponent: DeviceOwnerComponent by locator 53 private val profileOwnersComponent: ProfileOwnersComponent by locator 54 private val testAppsComponent: TestAppsComponent by locator 55 private val usersComponent: UsersComponent by locator 56 private val accountsComponent: AccountsComponent by locator 57 private val userTypeResolver: UserTypeResolver by locator 58 private var devicePolicyManagerRoleHolder: RemoteDevicePolicyManagerRoleHolder? = null 59 private var delegateDpc: RemotePolicyManager? = null 60 var primaryPolicyManager: RemotePolicyManager? = null 61 62 /** 63 * See [EnsureHasDelegate] 64 */ ensureHasDelegatenull65 fun ensureHasDelegate(annotation: EnsureHasDelegate) { 66 val dpc: RemotePolicyManager = getDeviceAdmin(annotation.admin) 67 val specifiesAdminType = annotation.admin != EnsureHasDelegate.AdminType.PRIMARY 68 val currentPrimaryPolicyManagerIsNotDelegator = 69 primaryPolicyManager != dpc 70 check( 71 !annotation.isPrimary || primaryPolicyManager == null || 72 (!specifiesAdminType && !currentPrimaryPolicyManagerIsNotDelegator) 73 ) { 74 "Only one DPC can be marked as primary per test " + 75 "(current primary is $primaryPolicyManager)" 76 } 77 testAppsComponent.ensureTestAppInstalled( 78 EnsureHasDelegate.DELEGATE_KEY, 79 RemoteDelegate.sTestApp, 80 dpc.user() 81 ) 82 val delegate = RemoteDelegate(RemoteDelegate.sTestApp, dpc().user()) 83 dpc.devicePolicyManager().setDelegatedScopes( 84 dpc.componentName(), 85 delegate.packageName(), 86 annotation.scopes.toList() 87 ) 88 if (annotation.isPrimary) { 89 delegateDpc = dpc 90 primaryPolicyManager = delegate 91 } 92 } 93 94 /** 95 * See [EnsureHasDevicePolicyManagerRoleHolder] 96 */ ensureHasDevicePolicyManagerRoleHoldernull97 fun ensureHasDevicePolicyManagerRoleHolder(onUser: UserType, isPrimary: Boolean) { 98 val user: UserReference = userTypeResolver.toUser(onUser) 99 accountsComponent.ensureHasNoAccounts( 100 UserType.ANY, 101 allowPreCreatedAccounts = true, 102 FailureMode.FAIL 103 ) 104 testAppsComponent.ensureTestAppInstalled(RemoteDevicePolicyManagerRoleHolder.sTestApp, user) 105 devicePolicy().setDevicePolicyManagementRoleHolder( 106 RemoteDevicePolicyManagerRoleHolder.sTestApp.pkg(), 107 user 108 ) 109 devicePolicyManagerRoleHolder = RemoteDevicePolicyManagerRoleHolder( 110 RemoteDevicePolicyManagerRoleHolder.sTestApp, user) 111 if (isPrimary) { 112 // We will override the existing primary 113 if (primaryPolicyManager != null) { 114 Log.i( 115 LOG_TAG, 116 "Overriding primary policy manager $primaryPolicyManager" + 117 " with $devicePolicyManagerRoleHolder" 118 ) 119 } 120 primaryPolicyManager = devicePolicyManagerRoleHolder 121 } 122 } 123 teardownShareableStatenull124 override fun teardownShareableState() { 125 devicePolicyManagerRoleHolder?.let { 126 devicePolicy().unsetDevicePolicyManagementRoleHolder( 127 it.testApp().pkg(), 128 it.user() 129 ) 130 devicePolicyManagerRoleHolder = null 131 } 132 } 133 teardownNonShareableStatenull134 override fun teardownNonShareableState() { 135 delegateDpc = null 136 primaryPolicyManager = null 137 } 138 139 /** 140 * See [com.android.bedstead.harrier.DeviceState.dpmRoleHolder] 141 */ dpmRoleHoldernull142 fun dpmRoleHolder(): RemoteDevicePolicyManagerRoleHolder { 143 return checkNotNull(devicePolicyManagerRoleHolder) { 144 "No Harrier-managed device policy manager role holder." 145 } 146 } 147 getDeviceAdminnull148 private fun getDeviceAdmin(adminType: EnsureHasDelegate.AdminType): RemotePolicyManager { 149 return when (adminType) { 150 EnsureHasDelegate.AdminType.DEVICE_OWNER -> deviceOwnerComponent.deviceOwner() 151 EnsureHasDelegate.AdminType.PROFILE_OWNER -> profileOwnersComponent.profileOwner() 152 EnsureHasDelegate.AdminType.PRIMARY -> dpc() 153 } 154 } 155 156 /** 157 * See [com.android.bedstead.harrier.DeviceState.dpc] 158 */ dpcnull159 fun dpc(): RemotePolicyManager { 160 primaryPolicyManager?.let { 161 return it 162 } 163 val profileOwner = profileOwnersComponent.getExistingProfileOwner(users().instrumented()) 164 if (profileOwner != null) { 165 if (RemoteDpc.isRemoteDpc(profileOwner)) { 166 return RemoteDpc.forDevicePolicyController(profileOwner) 167 } 168 } 169 deviceOwnerComponent.getDeviceOwner()?.let { 170 if (RemoteDpc.isRemoteDpc(it)) { 171 return RemoteDpc.forDevicePolicyController(it) 172 } 173 } 174 throw IllegalStateException( 175 "No Harrier-managed profile owner or device owner. " + 176 "Ensure you have set up the DPC using bedstead annotations." 177 ) 178 } 179 180 /** 181 * See [EnsureHasNoDelegate] 182 */ ensureHasNoDelegatenull183 fun ensureHasNoDelegate(adminType: EnsureHasNoDelegate.AdminType) { 184 if (adminType == EnsureHasNoDelegate.AdminType.ANY) { 185 for (user in users().all()) { 186 testAppsComponent.ensureTestAppNotInstalled(RemoteDelegate.sTestApp, user) 187 } 188 return 189 } 190 val dpc: RemotePolicyManager = when (adminType) { 191 EnsureHasNoDelegate.AdminType.PRIMARY -> primaryPolicyManager!! 192 EnsureHasNoDelegate.AdminType.DEVICE_OWNER -> deviceOwnerComponent.deviceOwner() 193 EnsureHasNoDelegate.AdminType.PROFILE_OWNER -> profileOwnersComponent.profileOwner() 194 else -> throw IllegalStateException("Unknown Admin Type $adminType") 195 } 196 testAppsComponent.ensureTestAppNotInstalled(RemoteDelegate.sTestApp, dpc.user()) 197 } 198 199 /** 200 * See [com.android.bedstead.harrier.DeviceState.dpcOnly] 201 */ dpcOnlynull202 fun dpcOnly(): RemotePolicyManager { 203 if (primaryPolicyManager != null) { 204 if (primaryPolicyManager!!.isDelegate) { 205 return delegateDpc!! 206 } 207 } 208 209 return dpc() 210 } 211 212 /** 213 * See [EnsureHasWorkProfile] 214 */ ensureHasWorkProfilenull215 fun ensureHasWorkProfile(annotation: EnsureHasWorkProfile) { 216 annotation.logic() 217 } 218 EnsureHasWorkProfilenull219 private fun EnsureHasWorkProfile.logic() { 220 val forUserReference: UserReference = userTypeResolver.toUser(forUser) 221 val profile = usersComponent.ensureHasProfile( 222 profileType = EnsureHasWorkProfile.PROFILE_TYPE, 223 forUserReference, 224 isQuietModeEnabled, 225 installInstrumentedApp 226 ) 227 profileOwnersComponent.ensureHasProfileOwner( 228 profile, 229 dpcIsPrimary, 230 useParentInstanceOfDpc, 231 affiliationIds = null, 232 dpcKey, 233 TestAppProvider().query(dpc) 234 ) 235 usersComponent.ensureSwitchedToUser(switchedToParentUser, forUserReference) 236 237 if (isOrganizationOwned) { 238 // It doesn't make sense to have COPE + DO 239 deviceOwnerComponent.ensureHasNoDeviceOwner() 240 } 241 242 val profileOwner = profileOwnersComponent 243 .profileOwner(workProfile(forUser)) 244 .devicePolicyController() as ProfileOwner 245 profileOwner.setIsOrganizationOwned(isOrganizationOwned) 246 } 247 248 /** 249 * See [RequireRunOnWorkProfile] 250 */ requireRunOnWorkProfilenull251 fun requireRunOnWorkProfile(annotation: RequireRunOnWorkProfile) { 252 annotation.logic() 253 } 254 logicnull255 private fun RequireRunOnWorkProfile.logic() { 256 val instrumentedUser = usersComponent.requireRunOnProfile( 257 userType = RequireRunOnWorkProfile.PROFILE_TYPE, 258 installInstrumentedAppInParent 259 ) 260 261 profileOwnersComponent.ensureHasProfileOwner( 262 instrumentedUser, 263 dpcIsPrimary, 264 useParentInstance = false, 265 affiliationIds.toSet(), 266 dpcKey, 267 TestAppProvider().query(dpc) 268 ) 269 usersComponent.ensureSwitchedToUser(switchedToParentUser, instrumentedUser.parent()!!) 270 271 if (isOrganizationOwned) { 272 // It doesn't make sense to have COPE + DO 273 deviceOwnerComponent.ensureHasNoDeviceOwner() 274 } 275 276 val profileOwner = profileOwnersComponent 277 .profileOwner(workProfile()) 278 .devicePolicyController() as ProfileOwner 279 profileOwner.setIsOrganizationOwned(isOrganizationOwned) 280 } 281 282 /** 283 * See [com.android.bedstead.harrier.DeviceState.workProfile] 284 */ workProfilenull285 fun workProfile(): UserReference { 286 return workProfile(forUser = UserType.INITIAL_USER) 287 } 288 289 /** 290 * See [com.android.bedstead.harrier.DeviceState.workProfile] 291 */ workProfilenull292 fun workProfile(forUser: UserType): UserReference { 293 return workProfile(userTypeResolver.toUser(forUser)) 294 } 295 296 /** 297 * See [com.android.bedstead.harrier.DeviceState.workProfile] 298 */ workProfilenull299 fun workProfile(forUser: UserReference): UserReference { 300 return usersComponent.profile( 301 com.android.bedstead.nene.users.UserType.MANAGED_PROFILE_TYPE_NAME, 302 forUser 303 ) 304 } 305 ensureTestAppInstalledAsPrimaryDPCnull306 fun ensureTestAppInstalledAsPrimaryDPC(annotation: EnsureTestAppInstalledAsPrimaryDPC) { 307 val testAppInstance: TestAppInstance? = testAppsComponent.ensureTestAppInstalled( 308 annotation.key, 309 annotation.query, 310 userTypeResolver.toUser(annotation.onUser) 311 ) 312 313 check(primaryPolicyManager == null) { 314 ("Only one DPC can be marked as primary per test (current primary is " + 315 primaryPolicyManager + ")") 316 } 317 primaryPolicyManager = RemoteTestApp(testAppInstance) 318 } 319 320 companion object { 321 const val LOG_TAG = "EnterpriseComponent" 322 } 323 } 324