1 /* 2 * Copyright (C) 2022 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.telephony.qns; 18 19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 20 21 import static org.junit.Assert.*; 22 import static org.mockito.Mockito.*; 23 24 import android.location.Country; 25 import android.net.ConnectivityManager; 26 import android.net.Network; 27 import android.net.NetworkCapabilities; 28 import android.net.TelephonyNetworkSpecifier; 29 import android.net.vcn.VcnTransportInfo; 30 import android.os.Handler; 31 import android.os.HandlerThread; 32 import android.os.Message; 33 34 import org.junit.After; 35 import org.junit.Before; 36 import org.junit.Test; 37 import org.junit.runner.RunWith; 38 import org.junit.runners.JUnit4; 39 import org.mockito.ArgumentCaptor; 40 import org.mockito.Mock; 41 import org.mockito.MockitoAnnotations; 42 import org.mockito.MockitoSession; 43 44 import java.util.concurrent.CountDownLatch; 45 import java.util.concurrent.Executor; 46 import java.util.concurrent.TimeUnit; 47 import java.util.function.Consumer; 48 49 @RunWith(JUnit4.class) 50 public class IwlanNetworkStatusTrackerTest extends QnsTest { 51 52 private static final int INVALID_SUB_ID = -1; 53 private static final int CURRENT_SLOT_ID = 0; 54 private static final int CURRENT_SUB_ID = 0; 55 private static final int ACTIVE_DATA_SUB_ID = 1; 56 private IwlanNetworkStatusTracker mIwlanNetworkStatusTracker; 57 private IwlanNetworkStatusTracker.IwlanAvailabilityInfo mIwlanAvailabilityInfo; 58 private final TestHandler[] mHandlers = new TestHandler[2]; 59 private Handler mEventHandler; 60 private final HandlerThread[] mHandlerThreads = new HandlerThread[2]; 61 @Mock private Network mMockNetwork; 62 private MockitoSession mMockSession; 63 private NetworkCapabilities mNetworkCapabilities; 64 65 private class TestHandlerThread extends HandlerThread { TestHandlerThread()66 TestHandlerThread() { 67 super(""); 68 } 69 70 @Override onLooperPrepared()71 protected void onLooperPrepared() { 72 super.onLooperPrepared(); 73 setReady(true); 74 } 75 } 76 77 private class TestHandler extends Handler { 78 private int mSlotId; 79 CountDownLatch mLatch; 80 TestHandler(HandlerThread ht, int slotId)81 TestHandler(HandlerThread ht, int slotId) { 82 super(ht.getLooper()); 83 mSlotId = slotId; 84 } 85 86 @Override handleMessage(Message msg)87 public void handleMessage(Message msg) { 88 super.handleMessage(msg); 89 QnsAsyncResult ar = (QnsAsyncResult) msg.obj; 90 mIwlanAvailabilityInfo = (IwlanNetworkStatusTracker.IwlanAvailabilityInfo) ar.mResult; 91 if (mLatch != null) { 92 mLatch.countDown(); 93 } 94 } 95 } 96 97 @Before setUp()98 public void setUp() throws Exception { 99 MockitoAnnotations.initMocks(this); 100 super.setUp(); 101 mMockSession = mockitoSession().mockStatic(QnsUtils.class).startMocking(); 102 mHandlerThreads[0] = new TestHandlerThread(); 103 mHandlerThreads[0].start(); 104 waitUntilReady(); 105 mHandlerThreads[1] = new TestHandlerThread(); 106 mHandlerThreads[1].start(); 107 waitUntilReady(); 108 mIwlanNetworkStatusTracker = new IwlanNetworkStatusTracker(sMockContext); 109 mIwlanNetworkStatusTracker.initBySlotIndex( 110 mMockQnsConfigManager, 111 mMockQnsEventDispatcher, 112 mMockQnsImsManager, 113 mMockQnsTelephonyListener, 114 0); 115 mIwlanNetworkStatusTracker.initBySlotIndex( 116 mMockQnsConfigManager, 117 mMockQnsEventDispatcher, 118 mMockQnsImsManager, 119 mMockQnsTelephonyListener, 120 1); 121 mHandlers[0] = new TestHandler(mHandlerThreads[0], 0); 122 mHandlers[1] = new TestHandler(mHandlerThreads[1], 1); 123 } 124 125 @After tearDown()126 public void tearDown() { 127 for (HandlerThread handlerThread : mHandlerThreads) { 128 if (handlerThread != null) { 129 handlerThread.quit(); 130 } 131 } 132 if (mIwlanNetworkStatusTracker != null) { 133 mIwlanNetworkStatusTracker.unregisterIwlanNetworksChanged(0, mHandlers[0]); 134 mIwlanNetworkStatusTracker.unregisterIwlanNetworksChanged(1, mHandlers[1]); 135 mIwlanNetworkStatusTracker.close(); 136 } 137 mIwlanAvailabilityInfo = null; 138 mMockSession.finishMocking(); 139 } 140 141 @Test testHandleMessage_InvalidSubID()142 public void testHandleMessage_InvalidSubID() throws InterruptedException { 143 mEventHandler = mIwlanNetworkStatusTracker.mHandlerSparseArray.get(CURRENT_SLOT_ID); 144 mHandlers[0].mLatch = new CountDownLatch(1); 145 mIwlanNetworkStatusTracker.registerIwlanNetworksChanged(CURRENT_SLOT_ID, mHandlers[0], 1); 146 waitForLastHandlerAction(mEventHandler); 147 assertTrue(mHandlers[0].mLatch.await(200, TimeUnit.MILLISECONDS)); 148 149 // If sim is invalid, no event is notified because of already info was notified. 150 mHandlers[0].mLatch = new CountDownLatch(1); 151 prepareNetworkCapabilitiesForTest(INVALID_SUB_ID, false /* isVcn */); 152 mIwlanNetworkStatusTracker.onCrossSimEnabledEvent(true, 0); 153 assertFalse(mHandlers[0].mLatch.await(100, TimeUnit.MILLISECONDS)); 154 assertNotNull(mIwlanAvailabilityInfo); 155 assertFalse(mIwlanAvailabilityInfo.isCrossWfc()); 156 } 157 158 @Test testHandleMessage_ValidSubID()159 public void testHandleMessage_ValidSubID() throws InterruptedException { 160 mEventHandler = mIwlanNetworkStatusTracker.mHandlerSparseArray.get(CURRENT_SLOT_ID); 161 mHandlers[0].mLatch = new CountDownLatch(1); 162 lenient().when(QnsUtils.getSubId(sMockContext, CURRENT_SLOT_ID)).thenReturn(CURRENT_SUB_ID); 163 lenient().when(QnsUtils.isCrossSimCallingEnabled(mMockQnsImsManager)).thenReturn(true); 164 lenient().when(QnsUtils.isDefaultDataSubs(CURRENT_SLOT_ID)).thenReturn(false); 165 mIwlanNetworkStatusTracker.registerIwlanNetworksChanged(CURRENT_SLOT_ID, mHandlers[0], 1); 166 waitForLastHandlerAction(mEventHandler); 167 assertTrue(mHandlers[0].mLatch.await(200, TimeUnit.MILLISECONDS)); 168 prepareNetworkCapabilitiesForTest(ACTIVE_DATA_SUB_ID, false /* isVcn */); 169 mIwlanNetworkStatusTracker.onCrossSimEnabledEvent(true, CURRENT_SLOT_ID); 170 mIwlanNetworkStatusTracker.onIwlanServiceStateChanged(CURRENT_SLOT_ID, true); 171 waitForLastHandlerAction(mEventHandler); 172 assertNotNull(mIwlanAvailabilityInfo); 173 assertTrue(mIwlanAvailabilityInfo.isCrossWfc()); 174 } 175 176 @Test testHandleMessage_ValidSubID_DDS_over_nDDS()177 public void testHandleMessage_ValidSubID_DDS_over_nDDS() throws InterruptedException { 178 // Verifies that DDS can also establish cross-sim over nDDS, as long as nDDS is the current 179 // active data sub. 180 mHandlers[0].mLatch = new CountDownLatch(1); 181 mEventHandler = mIwlanNetworkStatusTracker.mHandlerSparseArray.get(CURRENT_SLOT_ID); 182 lenient().when(QnsUtils.getSubId(sMockContext, CURRENT_SLOT_ID)).thenReturn(CURRENT_SUB_ID); 183 lenient().when(QnsUtils.isCrossSimCallingEnabled(mMockQnsImsManager)).thenReturn(true); 184 lenient().when(QnsUtils.isDefaultDataSubs(CURRENT_SLOT_ID)).thenReturn(false); 185 mIwlanNetworkStatusTracker.registerIwlanNetworksChanged(CURRENT_SLOT_ID, mHandlers[0], 1); 186 waitForLastHandlerAction(mEventHandler); 187 assertTrue(mHandlers[0].mLatch.await(200, TimeUnit.MILLISECONDS)); 188 prepareNetworkCapabilitiesForTest(ACTIVE_DATA_SUB_ID, false /* isVcn */); 189 mIwlanNetworkStatusTracker.onCrossSimEnabledEvent(true, CURRENT_SLOT_ID); 190 mIwlanNetworkStatusTracker.onIwlanServiceStateChanged(CURRENT_SLOT_ID, true); 191 waitForLastHandlerAction(mEventHandler); 192 assertNotNull(mIwlanAvailabilityInfo); 193 assertTrue(mIwlanAvailabilityInfo.isCrossWfc()); 194 } 195 196 @Test testHandleMessage_VcnWithValidSubID()197 public void testHandleMessage_VcnWithValidSubID() throws InterruptedException { 198 mHandlers[0].mLatch = new CountDownLatch(1); 199 mEventHandler = mIwlanNetworkStatusTracker.mHandlerSparseArray.get(CURRENT_SLOT_ID); 200 lenient().when(QnsUtils.getSubId(sMockContext, CURRENT_SLOT_ID)).thenReturn(CURRENT_SUB_ID); 201 lenient().when(QnsUtils.isCrossSimCallingEnabled(mMockQnsImsManager)).thenReturn(true); 202 lenient().when(QnsUtils.isDefaultDataSubs(CURRENT_SLOT_ID)).thenReturn(false); 203 mIwlanNetworkStatusTracker.registerIwlanNetworksChanged(CURRENT_SLOT_ID, mHandlers[0], 1); 204 waitForLastHandlerAction(mEventHandler); 205 assertTrue(mHandlers[0].mLatch.await(200, TimeUnit.MILLISECONDS)); 206 prepareNetworkCapabilitiesForTest(ACTIVE_DATA_SUB_ID, true /* isVcn */); 207 mIwlanNetworkStatusTracker.onCrossSimEnabledEvent(true, CURRENT_SLOT_ID); 208 mIwlanNetworkStatusTracker.onIwlanServiceStateChanged(CURRENT_SLOT_ID, true); 209 waitForLastHandlerAction(mEventHandler); 210 assertNotNull(mIwlanAvailabilityInfo); 211 assertTrue(mIwlanAvailabilityInfo.isCrossWfc()); 212 } 213 prepareNetworkCapabilitiesForTest(int subId, boolean isVcn)214 private void prepareNetworkCapabilitiesForTest(int subId, boolean isVcn) { 215 NetworkCapabilities.Builder builder = 216 new NetworkCapabilities.Builder() 217 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); 218 if (isVcn) { 219 builder.setTransportInfo(new VcnTransportInfo(subId)); 220 } else { 221 builder.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)); 222 } 223 mNetworkCapabilities = builder.build(); 224 when(mMockConnectivityManager.getActiveNetwork()).thenReturn(mMockNetwork); 225 when(mMockConnectivityManager.getNetworkCapabilities(mMockNetwork)) 226 .thenReturn(mNetworkCapabilities); 227 } 228 229 @Test testHandleMessage_DisableCrossSim()230 public void testHandleMessage_DisableCrossSim() throws InterruptedException { 231 testHandleMessage_ValidSubID(); 232 mHandlers[0].mLatch = new CountDownLatch(1); 233 lenient().when(QnsUtils.isCrossSimCallingEnabled(mMockQnsImsManager)).thenReturn(false); 234 lenient().when(QnsUtils.isDefaultDataSubs(CURRENT_SLOT_ID)).thenReturn(false); 235 mIwlanNetworkStatusTracker.onCrossSimEnabledEvent(false, 0); 236 assertTrue(mHandlers[0].mLatch.await(100, TimeUnit.MILLISECONDS)); 237 assertNotNull(mIwlanAvailabilityInfo); 238 assertFalse(mIwlanAvailabilityInfo.isCrossWfc()); 239 } 240 setupNetworkCallback()241 private ConnectivityManager.NetworkCallback setupNetworkCallback() { 242 ArgumentCaptor<ConnectivityManager.NetworkCallback> callbackArg = 243 ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class); 244 verify(mMockConnectivityManager, atLeastOnce()) 245 .registerDefaultNetworkCallback(callbackArg.capture(), isA(Handler.class)); 246 ConnectivityManager.NetworkCallback networkCallback = callbackArg.getValue(); 247 assertNotNull(networkCallback); 248 return networkCallback; 249 } 250 251 @Test testDefaultNetworkCallback_Wifi()252 public void testDefaultNetworkCallback_Wifi() throws InterruptedException { 253 testDefaultNetworkCallback(true, true); 254 } 255 256 @Test testDefaultNetworkCallback_Cellular()257 public void testDefaultNetworkCallback_Cellular() throws InterruptedException { 258 testDefaultNetworkCallback(false, false); 259 } 260 testDefaultNetworkCallback(boolean isWifi, boolean isIwlanRegistered)261 public void testDefaultNetworkCallback(boolean isWifi, boolean isIwlanRegistered) 262 throws InterruptedException { 263 mHandlers[0].mLatch = new CountDownLatch(1); 264 mEventHandler = mIwlanNetworkStatusTracker.mHandlerSparseArray.get(CURRENT_SLOT_ID); 265 mIwlanNetworkStatusTracker.registerIwlanNetworksChanged(0, mHandlers[0], 1); 266 waitForLastHandlerAction(mEventHandler); 267 assertTrue(mHandlers[0].mLatch.await(200, TimeUnit.MILLISECONDS)); 268 ConnectivityManager.NetworkCallback networkCallback = setupNetworkCallback(); 269 TelephonyNetworkSpecifier tns = new TelephonyNetworkSpecifier(0); 270 mNetworkCapabilities = 271 new NetworkCapabilities.Builder() 272 .addTransportType( 273 isWifi 274 ? NetworkCapabilities.TRANSPORT_WIFI 275 : NetworkCapabilities.TRANSPORT_CELLULAR) 276 .setNetworkSpecifier(tns) 277 .build(); 278 when(mMockConnectivityManager.getNetworkCapabilities(mMockNetwork)) 279 .thenReturn(mNetworkCapabilities); 280 networkCallback.onAvailable(mMockNetwork); 281 if (isWifi) { 282 mIwlanNetworkStatusTracker.onIwlanServiceStateChanged(0, isIwlanRegistered); 283 } 284 waitForLastHandlerAction(mEventHandler); 285 verifyIwlanAvailabilityInfo(isWifi, isIwlanRegistered); 286 287 networkCallback.onCapabilitiesChanged(mMockNetwork, mNetworkCapabilities); 288 // no callback is expected since onAvailable already reported information 289 waitForLastHandlerAction(mEventHandler); 290 verifyIwlanAvailabilityInfo(isWifi, isIwlanRegistered); 291 } 292 verifyIwlanAvailabilityInfo(boolean isWifi, boolean isIwlanRegistered)293 private void verifyIwlanAvailabilityInfo(boolean isWifi, boolean isIwlanRegistered) { 294 assertNotNull(mIwlanAvailabilityInfo); 295 if (isWifi && isIwlanRegistered) { 296 assertTrue(mIwlanAvailabilityInfo.getIwlanAvailable()); 297 } else { 298 assertFalse(mIwlanAvailabilityInfo.getIwlanAvailable()); 299 } 300 assertFalse(mIwlanAvailabilityInfo.isCrossWfc()); 301 } 302 303 @Test testDefaultNetworkCallback_onLost()304 public void testDefaultNetworkCallback_onLost() throws InterruptedException { 305 testDefaultNetworkCallback(true, true); 306 mHandlers[0].mLatch = new CountDownLatch(1); 307 ConnectivityManager.NetworkCallback networkCallback = setupNetworkCallback(); 308 networkCallback.onLost(mMockNetwork); 309 assertTrue(mHandlers[0].mLatch.await(100, TimeUnit.MILLISECONDS)); 310 assertNotNull(mIwlanAvailabilityInfo); 311 assertFalse(mIwlanAvailabilityInfo.getIwlanAvailable()); 312 } 313 314 @Test testRegisterIwlanNetworksChanged()315 public void testRegisterIwlanNetworksChanged() throws Exception { 316 mEventHandler = mIwlanNetworkStatusTracker.mHandlerSparseArray.get(CURRENT_SLOT_ID); 317 mHandlers[0].mLatch = new CountDownLatch(1); 318 mIwlanNetworkStatusTracker.registerIwlanNetworksChanged(0, mHandlers[0], 1); 319 waitForLastHandlerAction(mEventHandler); 320 assertTrue(mHandlers[0].mLatch.await(100, TimeUnit.MILLISECONDS)); 321 assertNotNull(mIwlanAvailabilityInfo); 322 assertFalse(mIwlanAvailabilityInfo.getIwlanAvailable()); 323 assertFalse(mIwlanAvailabilityInfo.isCrossWfc()); 324 } 325 326 @Test testRegisterIwlanNetworksChanged_Validate()327 public void testRegisterIwlanNetworksChanged_Validate() throws Exception { 328 mEventHandler = mIwlanNetworkStatusTracker.mHandlerSparseArray.get(0); 329 when(mMockQnsConfigManager.blockIpv6OnlyWifi()).thenReturn(false); 330 mHandlers[0].mLatch = new CountDownLatch(2); 331 mHandlers[1].mLatch = new CountDownLatch(1); 332 333 // Count down 1 mHandlers[0].mLatch 334 mIwlanNetworkStatusTracker.registerIwlanNetworksChanged(0, mHandlers[0], 1); 335 waitForLastHandlerAction(mEventHandler); 336 337 mIwlanNetworkStatusTracker.mLastIwlanAvailabilityInfo.put(0, 338 mIwlanNetworkStatusTracker.new IwlanAvailabilityInfo(true, false)); 339 340 // When registering a new handler, if the IwlanAvailabilityInfo information is updated, 341 // the existing one is also notified. 342 // Count down 1 mHandlers[1].mLatch and Count down 1 mHandlers[0].mLatch as well 343 mIwlanNetworkStatusTracker.registerIwlanNetworksChanged(0, mHandlers[1], 1); 344 waitForLastHandlerAction(mEventHandler); 345 346 assertTrue(mHandlers[0].mLatch.await(100, TimeUnit.MILLISECONDS)); 347 assertTrue(mHandlers[1].mLatch.await(100, TimeUnit.MILLISECONDS)); 348 } 349 350 @Test testUnregisterIwlanNetworksChanged()351 public void testUnregisterIwlanNetworksChanged() throws InterruptedException { 352 mEventHandler = mIwlanNetworkStatusTracker.mHandlerSparseArray.get(CURRENT_SLOT_ID); 353 mHandlers[0].mLatch = new CountDownLatch(1); 354 mIwlanNetworkStatusTracker.registerIwlanNetworksChanged(CURRENT_SLOT_ID, mHandlers[0], 1); 355 waitForLastHandlerAction(mEventHandler); 356 assertTrue(mHandlers[0].mLatch.await(100, TimeUnit.MILLISECONDS)); 357 ConnectivityManager.NetworkCallback networkCallback = setupNetworkCallback(); 358 TelephonyNetworkSpecifier tns = new TelephonyNetworkSpecifier(CURRENT_SLOT_ID); 359 mNetworkCapabilities = 360 new NetworkCapabilities.Builder() 361 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) 362 .setNetworkSpecifier(tns) 363 .build(); 364 when(mMockConnectivityManager.getNetworkCapabilities(mMockNetwork)) 365 .thenReturn(mNetworkCapabilities); 366 mHandlers[0].mLatch = new CountDownLatch(1); 367 mIwlanNetworkStatusTracker.unregisterIwlanNetworksChanged(CURRENT_SLOT_ID, mHandlers[0]); 368 waitForLastHandlerAction(mEventHandler); 369 networkCallback.onAvailable(mMockNetwork); 370 assertFalse(mHandlers[0].mLatch.await(100, TimeUnit.MILLISECONDS)); 371 } 372 373 @Test testIsInternationalRoaming()374 public void testIsInternationalRoaming() { 375 boolean isInternationalRoaming; 376 mEventHandler = mIwlanNetworkStatusTracker.mHandlerSparseArray.get(CURRENT_SLOT_ID); 377 when(mMockTelephonyManager.getSimCountryIso()).thenReturn("CA"); 378 ArgumentCaptor<Consumer<Country>> capture = ArgumentCaptor.forClass(Consumer.class); 379 verify(mMockCountryDetector) 380 .registerCountryDetectorCallback(isA(Executor.class), capture.capture()); 381 Consumer<Country> countryConsumer = capture.getValue(); 382 383 countryConsumer.accept(new Country("US", Country.COUNTRY_SOURCE_LOCATION)); 384 waitForLastHandlerAction(mEventHandler); 385 386 isInternationalRoaming = mIwlanNetworkStatusTracker.isInternationalRoaming(anyInt()); 387 assertTrue(isInternationalRoaming); 388 389 countryConsumer.accept(new Country("CA", Country.COUNTRY_SOURCE_LOCATION)); 390 waitForLastHandlerAction(mEventHandler); 391 392 isInternationalRoaming = mIwlanNetworkStatusTracker.isInternationalRoaming(anyInt()); 393 assertFalse(isInternationalRoaming); 394 } 395 396 @Test testWifiDisabling()397 public void testWifiDisabling() throws InterruptedException { 398 testDefaultNetworkCallback(true, true); 399 mHandlers[0].mLatch = new CountDownLatch(1); 400 mIwlanNetworkStatusTracker.onWifiDisabling(); 401 assertTrue(mHandlers[0].mLatch.await(100, TimeUnit.MILLISECONDS)); 402 assertNotNull(mIwlanAvailabilityInfo); 403 assertFalse(mIwlanAvailabilityInfo.getIwlanAvailable()); 404 } 405 406 @Test testDefaultNetworkCallback_IwlanNotRegistered()407 public void testDefaultNetworkCallback_IwlanNotRegistered() throws InterruptedException { 408 testDefaultNetworkCallback(true, false); 409 } 410 411 @Test testWifiToggleQuickOffOn()412 public void testWifiToggleQuickOffOn() throws InterruptedException { 413 testWifiDisabling(); 414 mHandlers[0].mLatch = new CountDownLatch(1); 415 mIwlanNetworkStatusTracker.onWifiEnabled(); 416 assertTrue(mHandlers[0].mLatch.await(100, TimeUnit.MILLISECONDS)); 417 verifyIwlanAvailabilityInfo(true, true); 418 } 419 420 @Test testWifiToggleQuickOffOn_inCrossSimEnabledCondition()421 public void testWifiToggleQuickOffOn_inCrossSimEnabledCondition() throws InterruptedException { 422 mIwlanNetworkStatusTracker.onWifiEnabled(); 423 testHandleMessage_ValidSubID(); 424 mIwlanNetworkStatusTracker.onWifiDisabling(); 425 assertNotNull(mIwlanAvailabilityInfo); 426 assertTrue(mIwlanAvailabilityInfo.isCrossWfc()); 427 mIwlanNetworkStatusTracker.onWifiEnabled(); 428 assertNotNull(mIwlanAvailabilityInfo); 429 assertTrue(mIwlanAvailabilityInfo.isCrossWfc()); 430 } 431 } 432