1 /* 2 * Copyright (C) 2020 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.common; 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.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 22 23 import static com.android.managedprovisioning.TestUtils.createTestAdminExtras; 24 25 import static org.mockito.ArgumentMatchers.anyString; 26 import static org.mockito.Matchers.any; 27 import static org.mockito.Matchers.anyInt; 28 import static org.mockito.Matchers.eq; 29 import static org.mockito.Mockito.never; 30 import static org.mockito.Mockito.verify; 31 import static org.mockito.Mockito.when; 32 33 import android.app.Activity; 34 import android.content.ComponentName; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.ServiceConnection; 38 import android.content.SharedPreferences; 39 import android.os.Bundle; 40 import android.os.PersistableBundle; 41 import android.os.UserHandle; 42 import android.test.AndroidTestCase; 43 import android.test.suitebuilder.annotation.SmallTest; 44 45 import androidx.test.InstrumentationRegistry; 46 47 import com.android.managedprovisioning.TestUtils; 48 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker; 49 import com.android.managedprovisioning.model.ProvisioningParams; 50 import com.android.managedprovisioning.provisioning.Constants; 51 52 import org.mockito.ArgumentCaptor; 53 import org.mockito.Mock; 54 import org.mockito.MockitoAnnotations; 55 56 public class StartDpcInsideSuwServiceConnectionTest extends AndroidTestCase { 57 private static final String TEST_MDM_PACKAGE_NAME = "mdm.package.name"; 58 private static final String TEST_MDM_ADMIN_RECEIVER = TEST_MDM_PACKAGE_NAME + ".AdminReceiver"; 59 private static final ComponentName TEST_MDM_ADMIN = new ComponentName(TEST_MDM_PACKAGE_NAME, 60 TEST_MDM_ADMIN_RECEIVER); 61 private static final PersistableBundle TEST_MDM_EXTRA_BUNDLE = createTestAdminExtras(); 62 private static final int TEST_REQUEST_CODE = 3; 63 private static final String TEST_SUW_PACKAGE_NAME = "suw.package.name"; 64 private static final String TEST_SUW_SERVICE_CLASS = TEST_SUW_PACKAGE_NAME + ".TestService"; 65 private static final ComponentName TEST_SUW_COMPONENT_NAME = new ComponentName( 66 TEST_SUW_PACKAGE_NAME, TEST_SUW_SERVICE_CLASS); 67 68 @Mock private Activity mActivity; 69 @Mock private Activity mRestoredActivity; 70 @Mock private Utils mUtils; 71 @Mock private ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker; 72 @Mock private TransitionHelper mTransitionHelper; 73 @Mock private SharedPreferences mSharedPreferences; 74 75 private StartDpcInsideSuwServiceConnection mStartDpcInsideSuwServiceConnection; 76 private Runnable mDpcIntentSender; 77 private ProvisioningParams mParams; 78 private final Context mTargetContext = InstrumentationRegistry.getTargetContext(); 79 80 @Override setUp()81 public void setUp() throws Exception { 82 System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); 83 MockitoAnnotations.initMocks(this); 84 when(mUtils.canResolveIntentAsUser(any(Context.class), any(Intent.class), anyInt())) 85 .thenReturn(true); 86 87 final PolicyComplianceUtils policyComplianceUtils = new PolicyComplianceUtils(); 88 mParams = new ProvisioningParams.Builder() 89 .setDeviceAdminComponentName(TEST_MDM_ADMIN) 90 .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE) 91 .setAdminExtrasBundle(TEST_MDM_EXTRA_BUNDLE) 92 .build(); 93 94 when(mActivity.getSharedPreferences(anyString(), anyInt())).thenReturn(mSharedPreferences); 95 when(mActivity.getResources()).thenReturn(mTargetContext.getResources()); 96 when(mRestoredActivity.getSharedPreferences(anyString(), anyInt())) 97 .thenReturn(mSharedPreferences); 98 when(mRestoredActivity.getResources()).thenReturn(mTargetContext.getResources()); 99 100 mStartDpcInsideSuwServiceConnection = new StartDpcInsideSuwServiceConnection(); 101 Constants.ENABLE_CUSTOM_TRANSITIONS = true; 102 mDpcIntentSender = () -> 103 policyComplianceUtils.startPolicyComplianceActivityForResultIfResolved( 104 mActivity, mParams, TEST_REQUEST_CODE, mUtils, 105 mProvisioningAnalyticsTracker, mTransitionHelper); 106 } 107 108 @SmallTest testBindingSucceeds_serviceConnects()109 public void testBindingSucceeds_serviceConnects() { 110 // GIVEN that we can bind to the SUW NetworkInterceptService 111 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 112 .thenReturn(true); 113 114 // WHEN calling triggerDpcStart() 115 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 116 117 // THEN we bind to the SUW NetworkInterceptService 118 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 119 120 // WHEN connection to the NetworkInterceptService is established 121 mStartDpcInsideSuwServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 122 123 // THEN an intent is sent to the DPC 124 verifyDpcLaunched(mActivity); 125 126 // WHEN calling dpcFinished and unbind 127 mStartDpcInsideSuwServiceConnection.dpcFinished(); 128 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 129 130 // THEN we unbind from the NetworkInterceptService 131 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 132 } 133 134 @SmallTest testBindingSucceeds_instanceStateSavedAndRestoredBeforeServiceConnected()135 public void testBindingSucceeds_instanceStateSavedAndRestoredBeforeServiceConnected() { 136 // GIVEN that we can bind to the SUW NetworkInterceptService 137 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 138 .thenReturn(true); 139 140 // WHEN calling triggerDpcStart() 141 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 142 143 // THEN we bind to the SUW NetworkInterceptService 144 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 145 146 // WHEN saving state and calling unbind before a service connection was established 147 final Bundle savedInstanceState = new Bundle(); 148 mStartDpcInsideSuwServiceConnection.saveInstanceState(savedInstanceState); 149 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 150 151 // THEN we unbind from the NetworkInterceptService 152 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 153 154 // GIVEN that a restored activity can also bind to the SUW NetworkInterceptService 155 when(mRestoredActivity.bindService( 156 any(Intent.class), any(ServiceConnection.class), anyInt())).thenReturn(true); 157 158 // WHEN we restore the service connection from the saved state 159 final StartDpcInsideSuwServiceConnection restoredServiceConnection = 160 getRestoredServiceConnection(savedInstanceState); 161 162 // THEN we bind to the SUW NetworkInterceptService again 163 verifyBindServiceCalled(mRestoredActivity, restoredServiceConnection); 164 165 // WHEN connection to the NetworkInterceptService is now established 166 restoredServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 167 168 // THEN only one intent is sent to the DPC 169 verifyDpcLaunched(mRestoredActivity); 170 171 // WHEN calling dpcFinished and unbind 172 restoredServiceConnection.dpcFinished(); 173 restoredServiceConnection.unbind(mRestoredActivity); 174 175 // THEN we unbind from the NetworkInterceptService 176 verify(mRestoredActivity).unbindService(eq(restoredServiceConnection)); 177 } 178 179 @SmallTest testBindingSucceeds_instanceStateSavedAndRestoredAfterServiceConnected()180 public void testBindingSucceeds_instanceStateSavedAndRestoredAfterServiceConnected() { 181 // GIVEN that we can bind to the SUW NetworkInterceptService 182 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 183 .thenReturn(true); 184 185 // WHEN calling triggerDpcStart() 186 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 187 188 // THEN we bind to the SUW NetworkInterceptService 189 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 190 191 // WHEN connection to the NetworkInterceptService is now established 192 mStartDpcInsideSuwServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 193 194 // THEN only one intent is sent to the DPC 195 verifyDpcLaunched(mActivity); 196 197 // WHEN saving state and calling unbind after a service connection was established 198 final Bundle savedInstanceState = new Bundle(); 199 mStartDpcInsideSuwServiceConnection.saveInstanceState(savedInstanceState); 200 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 201 202 // THEN we unbind from the NetworkInterceptService 203 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 204 205 // GIVEN that a restored activity can also bind to the SUW NetworkInterceptService 206 when(mRestoredActivity.bindService( 207 any(Intent.class), any(ServiceConnection.class), anyInt())).thenReturn(true); 208 209 // WHEN we restore the service connection from the saved state 210 final StartDpcInsideSuwServiceConnection restoredServiceConnection = 211 getRestoredServiceConnection(savedInstanceState); 212 213 // THEN we bind to the SUW NetworkInterceptService again 214 verifyBindServiceCalled(mRestoredActivity, restoredServiceConnection); 215 216 // WHEN connection to the NetworkInterceptService is now established 217 restoredServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 218 219 // THEN no new intent is sent to the DPC 220 verify(mRestoredActivity, never()).startActivityForResultAsUser(any(Intent.class), anyInt(), 221 any(UserHandle.class)); 222 223 // WHEN calling dpcFinished and unbind 224 restoredServiceConnection.dpcFinished(); 225 restoredServiceConnection.unbind(mRestoredActivity); 226 227 // THEN we unbind from the NetworkInterceptService 228 verify(mRestoredActivity).unbindService(eq(restoredServiceConnection)); 229 } 230 231 @SmallTest testBindingSucceeds_instanceStateSavedAndRestoredAfterDpcFinished()232 public void testBindingSucceeds_instanceStateSavedAndRestoredAfterDpcFinished() { 233 // GIVEN that we can bind to the SUW NetworkInterceptService 234 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 235 .thenReturn(true); 236 237 // WHEN calling triggerDpcStart() 238 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 239 240 // THEN we bind to the SUW NetworkInterceptService 241 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 242 243 // WHEN connection to the NetworkInterceptService is now established 244 mStartDpcInsideSuwServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 245 246 // THEN only one intent is sent to the DPC 247 verifyDpcLaunched(mActivity); 248 249 // WHEN calling dpcFinished and unbind 250 mStartDpcInsideSuwServiceConnection.dpcFinished(); 251 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 252 253 // THEN we unbind from the NetworkInterceptService 254 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 255 256 // WHEN calling saveInstanceState() after we've unbound from the service 257 final Bundle savedInstanceState = new Bundle(); 258 mStartDpcInsideSuwServiceConnection.saveInstanceState(savedInstanceState); 259 260 // GIVEN that a restored activity can also bind to the SUW NetworkInterceptService 261 when(mRestoredActivity.bindService( 262 any(Intent.class), any(ServiceConnection.class), anyInt())).thenReturn(true); 263 264 // WHEN we restore the service connection from the saved state 265 final StartDpcInsideSuwServiceConnection restoredServiceConnection = 266 getRestoredServiceConnection(savedInstanceState); 267 268 // THEN we do not bind to the SUW NetworkInterceptService again 269 verify(mRestoredActivity, never()).bindService(any(Intent.class), 270 eq(restoredServiceConnection), anyInt()); 271 272 // THEN no new intent is sent to the DPC 273 verify(mRestoredActivity, never()).startActivityForResultAsUser(any(Intent.class), anyInt(), 274 any(UserHandle.class)); 275 276 // WHEN calling dpcFinished and unbind 277 restoredServiceConnection.dpcFinished(); 278 restoredServiceConnection.unbind(mRestoredActivity); 279 280 // THEN we do not unbind from the NetworkInterceptService 281 verify(mRestoredActivity, never()).unbindService(eq(restoredServiceConnection)); 282 } 283 284 @SmallTest testBindingSucceeds_serviceConnectsAndDisconnects()285 public void testBindingSucceeds_serviceConnectsAndDisconnects() { 286 // GIVEN that we can bind to the SUW NetworkInterceptService 287 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 288 .thenReturn(true); 289 290 // WHEN calling triggerDpcStart() 291 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 292 293 // THEN we bind to the SUW NetworkInterceptService 294 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 295 296 // WHEN connection to the NetworkInterceptService is established and then lost 297 mStartDpcInsideSuwServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 298 mStartDpcInsideSuwServiceConnection.onServiceDisconnected(TEST_SUW_COMPONENT_NAME); 299 300 // THEN only one intent is sent to the DPC 301 verifyDpcLaunched(mActivity); 302 303 // WHEN calling dpcFinished and unbind 304 mStartDpcInsideSuwServiceConnection.dpcFinished(); 305 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 306 307 // THEN we unbind from the NetworkInterceptService 308 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 309 } 310 311 @SmallTest testBindingSucceeds_serviceConnectsAndDisconnects_instanceStateSavedAndRestored()312 public void testBindingSucceeds_serviceConnectsAndDisconnects_instanceStateSavedAndRestored() { 313 // GIVEN that we can bind to the SUW NetworkInterceptService 314 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 315 .thenReturn(true); 316 317 // WHEN calling triggerDpcStart() 318 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 319 320 // THEN we bind to the SUW NetworkInterceptService 321 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 322 323 // WHEN connection to the NetworkInterceptService is established and then lost 324 mStartDpcInsideSuwServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 325 mStartDpcInsideSuwServiceConnection.onServiceDisconnected(TEST_SUW_COMPONENT_NAME); 326 327 // THEN only one intent is sent to the DPC 328 verifyDpcLaunched(mActivity); 329 330 // WHEN saving state and calling unbind after a service connection was established 331 final Bundle savedInstanceState = new Bundle(); 332 mStartDpcInsideSuwServiceConnection.saveInstanceState(savedInstanceState); 333 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 334 335 // THEN we unbind from the NetworkInterceptService 336 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 337 338 // GIVEN that a restored activity can also bind to the SUW NetworkInterceptService 339 when(mRestoredActivity.bindService( 340 any(Intent.class), any(ServiceConnection.class), anyInt())).thenReturn(true); 341 342 // WHEN we restore the service connection from the saved state 343 final StartDpcInsideSuwServiceConnection restoredServiceConnection = 344 getRestoredServiceConnection(savedInstanceState); 345 346 // THEN we bind to the SUW NetworkInterceptService again 347 verifyBindServiceCalled(mRestoredActivity, restoredServiceConnection); 348 349 // WHEN connection to the NetworkInterceptService is now established 350 restoredServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 351 352 // THEN no new intent is sent to the DPC 353 verify(mRestoredActivity, never()).startActivityForResultAsUser(any(Intent.class), anyInt(), 354 any(UserHandle.class)); 355 356 // WHEN calling dpcFinished and unbind 357 restoredServiceConnection.dpcFinished(); 358 restoredServiceConnection.unbind(mRestoredActivity); 359 360 // THEN we unbind from the NetworkInterceptService 361 verify(mRestoredActivity).unbindService(eq(restoredServiceConnection)); 362 } 363 364 @SmallTest testBindingSucceeds_serviceConnectsTwice()365 public void testBindingSucceeds_serviceConnectsTwice() { 366 // GIVEN that we can bind to the SUW NetworkInterceptService 367 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 368 .thenReturn(true); 369 370 // WHEN calling triggerDpcStart() 371 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 372 373 // THEN we bind to the SUW NetworkInterceptService 374 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 375 376 // WHEN connection to the NetworkInterceptService is established, lost, and then 377 // re-established 378 mStartDpcInsideSuwServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 379 mStartDpcInsideSuwServiceConnection.onServiceDisconnected(TEST_SUW_COMPONENT_NAME); 380 mStartDpcInsideSuwServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 381 382 // THEN only one intent is sent to the DPC 383 verifyDpcLaunched(mActivity); 384 385 // WHEN calling dpcFinished and unbind 386 mStartDpcInsideSuwServiceConnection.dpcFinished(); 387 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 388 389 // THEN we unbind from the NetworkInterceptService 390 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 391 } 392 393 @SmallTest testBindingSucceeds_serviceDies()394 public void testBindingSucceeds_serviceDies() { 395 // GIVEN that we can bind to the SUW NetworkInterceptService 396 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 397 .thenReturn(true); 398 399 // WHEN calling triggerDpcStart() 400 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 401 402 // THEN we bind to the SUW NetworkInterceptService 403 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 404 405 // WHEN connection to the NetworkInterceptService is established, but then dies 406 mStartDpcInsideSuwServiceConnection.onServiceConnected(TEST_SUW_COMPONENT_NAME, null); 407 mStartDpcInsideSuwServiceConnection.onBindingDied(TEST_SUW_COMPONENT_NAME); 408 409 // THEN only one intent is sent to the DPC 410 verifyDpcLaunched(mActivity); 411 412 // WHEN calling dpcFinished and unbind 413 mStartDpcInsideSuwServiceConnection.dpcFinished(); 414 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 415 416 // THEN we unbind from the NetworkInterceptService 417 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 418 } 419 420 @SmallTest testBindingSucceeds_nullBinding()421 public void testBindingSucceeds_nullBinding() { 422 // GIVEN that we can bind to the SUW NetworkInterceptService 423 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 424 .thenReturn(true); 425 426 // WHEN calling triggerDpcStart() 427 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 428 429 // THEN we bind to the SUW NetworkInterceptService 430 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 431 432 // WHEN the NetworkInterceptService returns a null binding 433 mStartDpcInsideSuwServiceConnection.onNullBinding(TEST_SUW_COMPONENT_NAME); 434 435 // THEN an intent is sent to the DPC 436 verifyDpcLaunched(mActivity); 437 438 // WHEN calling dpcFinished and unbind 439 mStartDpcInsideSuwServiceConnection.dpcFinished(); 440 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 441 442 // THEN we unbind from the NetworkInterceptService 443 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 444 } 445 446 @SmallTest testBindingSucceeds_nullBinding_instanceStateSavedAndRestored()447 public void testBindingSucceeds_nullBinding_instanceStateSavedAndRestored() { 448 // GIVEN that we can bind to the SUW NetworkInterceptService 449 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 450 .thenReturn(true); 451 452 // WHEN calling triggerDpcStart() 453 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 454 455 // THEN we bind to the SUW NetworkInterceptService 456 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 457 458 // WHEN the NetworkInterceptService returns a null binding 459 mStartDpcInsideSuwServiceConnection.onNullBinding(TEST_SUW_COMPONENT_NAME); 460 461 // THEN an intent is sent to the DPC 462 verifyDpcLaunched(mActivity); 463 464 // WHEN saving state and calling unbind after the null binding 465 final Bundle savedInstanceState = new Bundle(); 466 mStartDpcInsideSuwServiceConnection.saveInstanceState(savedInstanceState); 467 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 468 469 // THEN we unbind from the NetworkInterceptService 470 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 471 472 // GIVEN that a restored activity can bind to the SUW NetworkInterceptService 473 when(mRestoredActivity.bindService( 474 any(Intent.class), any(ServiceConnection.class), anyInt())).thenReturn(true); 475 476 // WHEN we restore the service connection from the saved state 477 final StartDpcInsideSuwServiceConnection restoredServiceConnection = 478 getRestoredServiceConnection(savedInstanceState); 479 480 // THEN we bind to the SUW NetworkInterceptService again 481 verifyBindServiceCalled(mRestoredActivity, restoredServiceConnection); 482 483 // WHEN the NetworkInterceptService returns a null binding again 484 restoredServiceConnection.onNullBinding(TEST_SUW_COMPONENT_NAME); 485 486 // THEN no new intent is sent to the DPC 487 verify(mRestoredActivity, never()).startActivityForResultAsUser(any(Intent.class), anyInt(), 488 any(UserHandle.class)); 489 490 // WHEN calling dpcFinished and unbind 491 restoredServiceConnection.dpcFinished(); 492 restoredServiceConnection.unbind(mRestoredActivity); 493 494 // THEN we unbind from the NetworkInterceptService 495 verify(mRestoredActivity).unbindService(eq(restoredServiceConnection)); 496 } 497 498 @SmallTest testBindingFails()499 public void testBindingFails() { 500 // GIVEN that we can't bind to the SUW NetworkInterceptService 501 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 502 .thenReturn(false); 503 504 // WHEN calling triggerDpcStart() 505 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 506 507 // THEN we attempt to bind to the SUW NetworkInterceptService 508 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 509 510 // THEN an intent is sent to the DPC, even though the service binding failed 511 verifyDpcLaunched(mActivity); 512 513 // WHEN calling dpcFinished and unbind 514 mStartDpcInsideSuwServiceConnection.dpcFinished(); 515 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 516 517 // THEN we unbind from the NetworkInterceptService even if binding failed 518 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 519 } 520 521 @SmallTest testBindingFails_instanceStateSavedAndRestored()522 public void testBindingFails_instanceStateSavedAndRestored() { 523 // GIVEN that we can't bind to the SUW NetworkInterceptService 524 when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt())) 525 .thenReturn(false); 526 527 // WHEN calling triggerDpcStart() 528 mStartDpcInsideSuwServiceConnection.triggerDpcStart(mActivity, mDpcIntentSender); 529 530 // THEN we attempt to bind to the SUW NetworkInterceptService 531 verifyBindServiceCalled(mActivity, mStartDpcInsideSuwServiceConnection); 532 533 // THEN an intent is sent to the DPC, even though the service binding failed 534 verifyDpcLaunched(mActivity); 535 536 // WHEN saving state and calling unbind after the binding failed 537 final Bundle savedInstanceState = new Bundle(); 538 mStartDpcInsideSuwServiceConnection.saveInstanceState(savedInstanceState); 539 mStartDpcInsideSuwServiceConnection.unbind(mActivity); 540 541 // THEN we unbind from the NetworkInterceptService even if binding failed 542 verify(mActivity).unbindService(eq(mStartDpcInsideSuwServiceConnection)); 543 544 // GIVEN that a restored activity could now bind to the SUW NetworkInterceptService 545 when(mRestoredActivity.bindService( 546 any(Intent.class), any(ServiceConnection.class), anyInt())).thenReturn(true); 547 548 // WHEN we restore the service connection from the saved state 549 final StartDpcInsideSuwServiceConnection restoredServiceConnection = 550 getRestoredServiceConnection(savedInstanceState); 551 552 // THEN we still do not bind to the SUW NetworkInterceptService 553 verify(mRestoredActivity, never()).bindService(any(Intent.class), 554 eq(restoredServiceConnection), anyInt()); 555 556 // THEN no new intent is sent to the DPC 557 verify(mRestoredActivity, never()).startActivityForResultAsUser(any(Intent.class), anyInt(), 558 any(UserHandle.class)); 559 560 // WHEN calling dpcFinished and unbind 561 restoredServiceConnection.dpcFinished(); 562 restoredServiceConnection.unbind(mRestoredActivity); 563 564 // THEN we do not unbind from the NetworkInterceptService 565 verify(mRestoredActivity, never()).unbindService(eq(restoredServiceConnection)); 566 } 567 verifyDpcLaunched(Activity activity)568 private void verifyDpcLaunched(Activity activity) { 569 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 570 verify(mTransitionHelper).startActivityForResultAsUserWithTransition( 571 eq(activity), intentCaptor.capture(), anyInt(), any(UserHandle.class)); 572 final String intentAction = intentCaptor.getValue().getAction(); 573 // THEN the intent should be ACTION_PROVISIONING_SUCCESSFUL 574 assertEquals(ACTION_ADMIN_POLICY_COMPLIANCE, intentAction); 575 // THEN the intent should only be sent to the dpc 576 assertEquals(TEST_MDM_PACKAGE_NAME, intentCaptor.getValue().getPackage()); 577 // THEN the admin extras bundle should contain mdm extras 578 assertExtras(intentCaptor.getValue()); 579 // THEN a metric should be logged 580 verify(mProvisioningAnalyticsTracker).logDpcSetupStarted(eq(activity), eq(intentAction)); 581 } 582 verifyBindServiceCalled(Activity activity, StartDpcInsideSuwServiceConnection serviceConnection)583 private void verifyBindServiceCalled(Activity activity, 584 StartDpcInsideSuwServiceConnection serviceConnection) { 585 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 586 verify(activity).bindService(intentCaptor.capture(), eq(serviceConnection), anyInt()); 587 // THEN the intent should be NETWORK_INTERCEPT_SERVICE_ACTION 588 assertEquals(StartDpcInsideSuwServiceConnection.NETWORK_INTERCEPT_SERVICE_ACTION, 589 intentCaptor.getValue().getAction()); 590 // THEN the intent should be sent to Setup Wizard 591 assertEquals(StartDpcInsideSuwServiceConnection.SETUP_WIZARD_PACKAGE_NAME, 592 intentCaptor.getValue().getPackage()); 593 } 594 assertExtras(Intent intent)595 private void assertExtras(Intent intent) { 596 assertTrue(TestUtils.bundleEquals(TEST_MDM_EXTRA_BUNDLE, 597 (PersistableBundle) intent.getExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE))); 598 } 599 getRestoredServiceConnection( Bundle savedInstanceState)600 private StartDpcInsideSuwServiceConnection getRestoredServiceConnection( 601 Bundle savedInstanceState) { 602 final PolicyComplianceUtils policyComplianceUtils = new PolicyComplianceUtils(); 603 final Runnable dpcIntentSenderForRestoredActivity = () -> 604 policyComplianceUtils.startPolicyComplianceActivityForResultIfResolved( 605 mRestoredActivity, mParams, TEST_REQUEST_CODE, 606 mUtils, mProvisioningAnalyticsTracker, mTransitionHelper); 607 608 return new StartDpcInsideSuwServiceConnection(mRestoredActivity, savedInstanceState, 609 dpcIntentSenderForRestoredActivity); 610 } 611 } 612