1 /* 2 * Copyright 2019, 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 17 package com.android.managedprovisioning.finalization; 18 19 import static android.app.admin.DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE; 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 21 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; 22 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 23 24 import static com.android.managedprovisioning.TestUtils.createTestAdminExtras; 25 26 import static com.google.common.truth.Truth.assertThat; 27 28 import static org.mockito.ArgumentMatchers.anyString; 29 import static org.mockito.Matchers.any; 30 import static org.mockito.Matchers.anyInt; 31 import static org.mockito.Matchers.eq; 32 import static org.mockito.Mockito.mock; 33 import static org.mockito.Mockito.never; 34 import static org.mockito.Mockito.times; 35 import static org.mockito.Mockito.verify; 36 import static org.mockito.Mockito.verifyNoMoreInteractions; 37 import static org.mockito.Mockito.verifyZeroInteractions; 38 import static org.mockito.Mockito.when; 39 40 import android.accounts.Account; 41 import android.app.Activity; 42 import android.app.admin.DevicePolicyManager; 43 import android.content.ComponentName; 44 import android.content.Context; 45 import android.content.Intent; 46 import android.content.ServiceConnection; 47 import android.content.SharedPreferences; 48 import android.content.pm.PackageManager; 49 import android.os.Bundle; 50 import android.os.PersistableBundle; 51 import android.os.UserHandle; 52 import android.os.UserManager; 53 import android.test.AndroidTestCase; 54 import android.test.suitebuilder.annotation.SmallTest; 55 56 import androidx.test.InstrumentationRegistry; 57 58 import com.android.managedprovisioning.TestUtils; 59 import com.android.managedprovisioning.analytics.DeferredMetricsReader; 60 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker; 61 import com.android.managedprovisioning.common.NotificationHelper; 62 import com.android.managedprovisioning.common.PolicyComplianceUtils; 63 import com.android.managedprovisioning.common.SettingsFacade; 64 import com.android.managedprovisioning.common.TransitionHelper; 65 import com.android.managedprovisioning.common.Utils; 66 import com.android.managedprovisioning.model.ProvisioningParams; 67 68 import org.mockito.ArgumentCaptor; 69 import org.mockito.Mock; 70 import org.mockito.MockitoAnnotations; 71 72 /** 73 * Unit tests for {@link FinalizationInsideSuwControllerLogic}. 74 */ 75 public class FinalizationInsideSuwControllerTest extends AndroidTestCase { 76 private static final UserHandle MANAGED_PROFILE_USER_HANDLE = UserHandle.of(123); 77 private static final String TEST_MDM_PACKAGE_NAME = "mdm.package.name"; 78 private static final String TEST_MDM_ADMIN_RECEIVER = TEST_MDM_PACKAGE_NAME + ".AdminReceiver"; 79 private static final ComponentName TEST_MDM_ADMIN = new ComponentName(TEST_MDM_PACKAGE_NAME, 80 TEST_MDM_ADMIN_RECEIVER); 81 private static final PersistableBundle TEST_MDM_EXTRA_BUNDLE = createTestAdminExtras(); 82 private static final Account TEST_ACCOUNT = new Account("test@account.com", "account.type"); 83 private static final Intent ACTIVITY_INTENT = 84 new Intent("android.app.action.PROVISION_FINALIZATION_INSIDE_SUW"); 85 86 @Mock private Activity mActivity; 87 @Mock private Utils mUtils; 88 @Mock private SettingsFacade mSettingsFacade; 89 @Mock private UserProvisioningStateHelper mHelper; 90 @Mock private NotificationHelper mNotificationHelper; 91 @Mock private DeferredMetricsReader mDeferredMetricsReader; 92 @Mock private ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker; 93 @Mock private UserManager mUserManager; 94 @Mock private SharedPreferences mSharedPreferences; 95 96 private PreFinalizationController mPreFinalizationController; 97 private FinalizationController mFinalizationController; 98 private final Context mTargetContext = InstrumentationRegistry.getTargetContext(); 99 @Mock private TransitionHelper mTransitionHelper; 100 101 @Override setUp()102 public void setUp() throws Exception { 103 // this is necessary for mockito to work 104 System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); 105 MockitoAnnotations.initMocks(this); 106 when(mUtils.canResolveIntentAsUser(any(Context.class), any(Intent.class), anyInt())) 107 .thenReturn(true); 108 when(mActivity.getFilesDir()).thenReturn(getContext().getFilesDir()); 109 when(mActivity.getIntent()).thenReturn(ACTIVITY_INTENT); 110 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 111 .thenReturn(false); 112 when(mActivity.getSystemServiceName(UserManager.class)) 113 .thenReturn(Context.USER_SERVICE); 114 when(mActivity.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); 115 when(mActivity.getSharedPreferences(anyString(), anyInt())).thenReturn(mSharedPreferences); 116 when(mActivity.getResources()).thenReturn(mTargetContext.getResources()); 117 when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true); 118 when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true); 119 120 final ProvisioningParamsUtils provisioningParamsUtils = new ProvisioningParamsUtils(); 121 mPreFinalizationController = new PreFinalizationController( 122 mActivity, mUtils, mSettingsFacade, mHelper, 123 provisioningParamsUtils, new SendDpcBroadcastServiceUtils()); 124 mFinalizationController = new FinalizationController( 125 mActivity, 126 new FinalizationInsideSuwControllerLogic( 127 mActivity, 128 mUtils, 129 new PolicyComplianceUtils(), 130 mProvisioningAnalyticsTracker, 131 mTransitionHelper), 132 mUtils, mSettingsFacade, mHelper, mNotificationHelper, mDeferredMetricsReader, 133 provisioningParamsUtils); 134 } 135 136 @Override tearDown()137 public void tearDown() throws Exception { 138 mFinalizationController.clearParamsFile(); 139 } 140 141 @SmallTest testFinalized_alreadyCalled()142 public void testFinalized_alreadyCalled() { 143 // GIVEN that deviceManagementEstablished has already been called 144 when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true); 145 final ProvisioningParams params = createProvisioningParams( 146 ACTION_PROVISION_MANAGED_PROFILE, false); 147 148 // WHEN calling provisioningFinalized and commitFinalizedState 149 mFinalizationController.provisioningFinalized(); 150 mFinalizationController.commitFinalizedState(); 151 152 // THEN nothing should happen 153 verify(mHelper, never()).markUserProvisioningStateInitiallyDone(params); 154 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 155 verifyZeroInteractions(mDeferredMetricsReader); 156 } 157 158 @SmallTest testFinalized_noParamsStored()159 public void testFinalized_noParamsStored() { 160 // GIVEN that the user provisioning state is correct 161 when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false); 162 163 // WHEN calling provisioningFinalized and commitFinalizedState 164 mFinalizationController.provisioningFinalized(); 165 mFinalizationController.commitFinalizedState(); 166 167 // THEN nothing should happen 168 verify(mHelper, never()) 169 .markUserProvisioningStateInitiallyDone(any(ProvisioningParams.class)); 170 verify(mHelper, never()).markUserProvisioningStateFinalized(any(ProvisioningParams.class)); 171 verifyZeroInteractions(mDeferredMetricsReader); 172 } 173 174 @SmallTest testManagedProfileFinalizationDuringSuw()175 public void testManagedProfileFinalizationDuringSuw() { 176 // GIVEN that deviceManagementEstablished has never been called 177 when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true); 178 // GIVEN that we've provisioned a managed profile after SUW 179 final ProvisioningParams params = createProvisioningParams( 180 ACTION_PROVISION_MANAGED_PROFILE, true); 181 when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(false); 182 when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(true); 183 when(mUtils.getManagedProfile(mActivity)).thenReturn(MANAGED_PROFILE_USER_HANDLE); 184 185 // WHEN calling deviceManagementEstablished 186 mPreFinalizationController.deviceManagementEstablished(params); 187 188 // THEN the user provisioning state should be marked as initially done 189 verify(mHelper).markUserProvisioningStateInitiallyDone(params); 190 // THEN the provisioning params have been stored and will be read in provisioningFinalized 191 192 // GIVEN that the provisioning state is now incomplete 193 when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false); 194 195 // WHEN we save and restore controller state 196 saveAndRestoreControllerState(); 197 198 // THEN the user provisioning state is not yet finalized 199 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 200 201 // THEN no intent should be sent to the dpc. 202 verify(mTransitionHelper, never()).startActivityForResultAsUserWithTransition( 203 eq(mActivity), any(Intent.class), anyInt(), eq(MANAGED_PROFILE_USER_HANDLE)); 204 205 // WHEN calling provisioningFinalized 206 mFinalizationController.provisioningFinalized(); 207 208 // THEN the user provisioning state is not yet finalized 209 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 210 211 // THEN intent should be sent to the dpc. 212 verifyDpcLaunchedForUser(MANAGED_PROFILE_USER_HANDLE, 1); 213 214 // WHEN calling provisioningFinalized again 215 mFinalizationController.provisioningFinalized(); 216 217 // THEN the user provisioning state is not yet finalized 218 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 219 220 // THEN intent should not be sent to the dpc again 221 verifyDpcLaunchedForUser(MANAGED_PROFILE_USER_HANDLE, 1); 222 223 // WHEN simulating a DPC cancel by calling activityDestroyed(true), and then 224 // provisioningFinalized again 225 mFinalizationController.activityDestroyed(true); 226 mFinalizationController.provisioningFinalized(); 227 228 // THEN the user provisioning state is not yet finalized 229 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 230 231 // THEN intent should be sent to the dpc again 232 verifyDpcLaunchedForUser(MANAGED_PROFILE_USER_HANDLE, 2); 233 234 // WHEN we save and restore controller state, and then call provisioningFinalized again 235 saveAndRestoreControllerState(); 236 mFinalizationController.provisioningFinalized(); 237 238 // THEN the user provisioning state is not yet finalized 239 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 240 241 // THEN intent is not sent to the dpc again 242 verifyDpcLaunchedForUser(MANAGED_PROFILE_USER_HANDLE, 2); 243 244 // WHEN the provisioning state changes are now committed 245 mFinalizationController.commitFinalizedState(); 246 247 // THEN deferred metrics have been written exactly once 248 verify(mDeferredMetricsReader).scheduleDumpMetrics(any(Context.class)); 249 verifyNoMoreInteractions(mDeferredMetricsReader); 250 251 // THEN the user provisioning state is finalized 252 verify(mHelper).markUserProvisioningStateFinalized(params); 253 254 // THEN the service which starts the DPC, has never been started. 255 verifySendDpcServiceNotStarted(); 256 } 257 258 @SmallTest testDeviceOwnerFinalizationDuringSuw()259 public void testDeviceOwnerFinalizationDuringSuw() { 260 // GIVEN that deviceManagementEstablished has never been called 261 when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true); 262 // GIVEN that we've provisioned a device owner during SUW 263 final ProvisioningParams params = createProvisioningParams( 264 ACTION_PROVISION_MANAGED_DEVICE, false); 265 when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(false); 266 when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(true); 267 268 // WHEN calling deviceManagementEstablished 269 mPreFinalizationController.deviceManagementEstablished(params); 270 271 // THEN the user provisioning state should be marked as initially done 272 verify(mHelper).markUserProvisioningStateInitiallyDone(params); 273 // THEN the provisioning params have been stored and will be read in provisioningFinalized 274 275 // GIVEN that the provisioning state is now incomplete 276 when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false); 277 278 // WHEN we save and restore controller state 279 saveAndRestoreControllerState(); 280 281 // THEN the user provisioning state is not yet finalized 282 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 283 284 // THEN no intent should be sent to the dpc. 285 verify(mTransitionHelper, never()).startActivityForResultAsUserWithTransition( 286 eq(mActivity), any(Intent.class), anyInt(), 287 eq(UserHandle.of(UserHandle.myUserId()))); 288 289 // WHEN calling provisioningFinalized 290 mFinalizationController.provisioningFinalized(); 291 292 // THEN the user provisioning state is not yet finalized 293 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 294 295 // THEN intent should be sent to the dpc. 296 verifyDpcLaunchedForUser(UserHandle.of(UserHandle.myUserId()), 1); 297 298 // WHEN calling provisioningFinalized again 299 mFinalizationController.provisioningFinalized(); 300 301 // THEN the user provisioning state is not yet finalized 302 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 303 304 // THEN intent should not be sent to the dpc again 305 verifyDpcLaunchedForUser(UserHandle.of(UserHandle.myUserId()), 1); 306 307 // WHEN simulating a DPC cancel by calling activityDestroyed(true), and then 308 // provisioningFinalized again 309 mFinalizationController.activityDestroyed(true); 310 mFinalizationController.provisioningFinalized(); 311 312 // THEN the user provisioning state is not yet finalized 313 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 314 315 // THEN intent should be sent to the dpc again 316 verifyDpcLaunchedForUser(UserHandle.of(UserHandle.myUserId()), 2); 317 318 // WHEN we save and restore controller state, and then call provisioningFinalized again 319 saveAndRestoreControllerState(); 320 mFinalizationController.provisioningFinalized(); 321 322 // THEN the user provisioning state is not yet finalized 323 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 324 325 // THEN intent should not be sent to the dpc again 326 verifyDpcLaunchedForUser(UserHandle.of(UserHandle.myUserId()), 2); 327 328 // WHEN the provisioning state changes are now committed 329 mFinalizationController.commitFinalizedState(); 330 331 // THEN deferred metrics have been written exactly once 332 verify(mDeferredMetricsReader).scheduleDumpMetrics(any(Context.class)); 333 verifyNoMoreInteractions(mDeferredMetricsReader); 334 335 // THEN the user provisioning state is finalized 336 verify(mHelper).markUserProvisioningStateFinalized(params); 337 338 // THEN a privacy reminder is shown to the user exactly once 339 verify(mNotificationHelper).showPrivacyReminderNotification(eq(mActivity), anyInt()); 340 341 // THEN no broadcast was ever sent to the primary user 342 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 343 verify(mActivity, never()).sendBroadcast(intentCaptor.capture()); 344 } 345 346 @SmallTest testCorpOwnedManagedProfileDuringSuw()347 public void testCorpOwnedManagedProfileDuringSuw() throws PackageManager.NameNotFoundException { 348 // GIVEN that deviceManagementEstablished has never been called 349 when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true); 350 // GIVEN that we're provisioning a corp-owned managed profile DURING SUW 351 final ProvisioningParams params = 352 createProvisioningParamsBuilder(ACTION_PROVISION_MANAGED_PROFILE, true) 353 .setIsOrganizationOwnedProvisioning(true) 354 .setFlowType(ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED) 355 .build(); 356 357 when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(false); 358 when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(true); 359 when(mUtils.getManagedProfile(mActivity)) 360 .thenReturn(MANAGED_PROFILE_USER_HANDLE); 361 362 // Mock DPM for testing access to device IDs is granted. 363 final DevicePolicyManager mockDpm = mock(DevicePolicyManager.class); 364 when(mActivity.getSystemServiceName(DevicePolicyManager.class)) 365 .thenReturn(Context.DEVICE_POLICY_SERVICE); 366 when(mActivity.getSystemService(DevicePolicyManager.class)).thenReturn(mockDpm); 367 final int managedProfileUserId = MANAGED_PROFILE_USER_HANDLE.getIdentifier(); 368 when(mockDpm.getProfileOwnerAsUser(managedProfileUserId)).thenReturn(TEST_MDM_ADMIN); 369 370 // Actual Device IDs access is granted to the DPM of the managed profile, in the context 371 // of the managed profile. 372 final Context profileContext = mock(Context.class); 373 when(mActivity.createPackageContextAsUser(mActivity.getPackageName(), /*flags=*/ 0, 374 MANAGED_PROFILE_USER_HANDLE)).thenReturn(profileContext); 375 when(profileContext.getSystemServiceName(DevicePolicyManager.class)) 376 .thenReturn(Context.DEVICE_POLICY_SERVICE); 377 final DevicePolicyManager mockProfileDpm = mock(DevicePolicyManager.class); 378 when(profileContext.getSystemService(DevicePolicyManager.class)).thenReturn(mockProfileDpm); 379 380 // WHEN calling deviceManagementEstablished 381 mPreFinalizationController.deviceManagementEstablished(params); 382 383 // THEN the user provisioning state should be marked as initially done 384 verify(mHelper).markUserProvisioningStateInitiallyDone(params); 385 386 // GIVEN that the provisioning state is now incomplete 387 when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false); 388 389 // WHEN calling provisioningFinalized 390 mFinalizationController.provisioningFinalized(); 391 392 // THEN the user provisioning state is not yet finalized 393 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 394 395 // THEN the DPC policy compliance screen should be shown on the work profile. 396 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 397 verify(mTransitionHelper).startActivityForResultAsUserWithTransition( 398 eq(mActivity), intentCaptor.capture(), anyInt(), eq(MANAGED_PROFILE_USER_HANDLE)); 399 assertThat(intentCaptor.getValue().getAction()) 400 .isEqualTo(DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE); 401 402 // WHEN calling provisioningFinalized again 403 mFinalizationController.provisioningFinalized(); 404 405 // THEN the user provisioning state is not yet finalized 406 verify(mHelper, never()).markUserProvisioningStateFinalized(params); 407 408 // THEN the DPC policy compliance screen should be shown on the work profile. 409 intentCaptor = ArgumentCaptor.forClass(Intent.class); 410 verify(mTransitionHelper).startActivityForResultAsUserWithTransition( 411 eq(mActivity), intentCaptor.capture(), anyInt(), eq(MANAGED_PROFILE_USER_HANDLE)); 412 assertThat(intentCaptor.getValue().getAction()) 413 .isEqualTo(DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE); 414 415 // WHEN the provisioning state changes are now committed 416 mFinalizationController.commitFinalizedState(); 417 418 // THEN deferred metrics are written exactly once 419 verify(mDeferredMetricsReader).scheduleDumpMetrics(any(Context.class)); 420 verifyNoMoreInteractions(mDeferredMetricsReader); 421 422 // THEN the user provisioning state is finalized 423 verify(mHelper).markUserProvisioningStateFinalized(params); 424 } 425 verifyDpcLaunchedForUser(UserHandle userHandle, int numTimes)426 private void verifyDpcLaunchedForUser(UserHandle userHandle, int numTimes) { 427 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 428 verify(mTransitionHelper, times(numTimes)).startActivityForResultAsUserWithTransition( 429 eq(mActivity), intentCaptor.capture(), anyInt(), eq(userHandle)); 430 final String intentAction = intentCaptor.getValue().getAction(); 431 // THEN the intent should be ACTION_PROVISIONING_SUCCESSFUL 432 assertEquals(ACTION_ADMIN_POLICY_COMPLIANCE, intentAction); 433 // THEN the intent should only be sent to the dpc 434 assertEquals(TEST_MDM_PACKAGE_NAME, intentCaptor.getValue().getPackage()); 435 // THEN the admin extras bundle should contain mdm extras 436 assertExtras(intentCaptor.getValue()); 437 // THEN a metric should be logged 438 verify(mProvisioningAnalyticsTracker, times(numTimes)).logDpcSetupStarted( 439 eq(mActivity), eq(intentAction)); 440 } 441 verifySendDpcServiceNotStarted()442 private void verifySendDpcServiceNotStarted() { 443 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 444 verify(mActivity, never()).startService(intentCaptor.capture()); 445 } 446 assertExtras(Intent intent)447 private void assertExtras(Intent intent) { 448 assertTrue(TestUtils.bundleEquals(TEST_MDM_EXTRA_BUNDLE, 449 (PersistableBundle) intent.getExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE))); 450 } 451 createProvisioningParams(String action, boolean migrateAccount)452 private ProvisioningParams createProvisioningParams(String action, boolean migrateAccount) { 453 return createProvisioningParamsBuilder(action, migrateAccount).build(); 454 } 455 createProvisioningParamsBuilder(String action, boolean migrateAccount)456 private ProvisioningParams.Builder createProvisioningParamsBuilder(String action, 457 boolean migrateAccount) { 458 ProvisioningParams.Builder builder = new ProvisioningParams.Builder() 459 .setDeviceAdminComponentName(TEST_MDM_ADMIN) 460 .setProvisioningAction(action) 461 .setAdminExtrasBundle(TEST_MDM_EXTRA_BUNDLE) 462 .setReturnBeforePolicyCompliance(true); 463 464 if (migrateAccount) { 465 builder.setAccountToMigrate(TEST_ACCOUNT); 466 builder.setKeepAccountMigrated(false); 467 } 468 469 return builder; 470 } 471 saveAndRestoreControllerState()472 private void saveAndRestoreControllerState() { 473 final Bundle savedInstanceState = new Bundle(); 474 mFinalizationController.saveInstanceState(savedInstanceState); 475 mFinalizationController.activityDestroyed(false); 476 mFinalizationController.restoreInstanceState(savedInstanceState); 477 } 478 } 479