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