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