• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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