1/*
2 * Copyright (C) 2016 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
17package com.android.internal.telephony.dataconnection;
18
19import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
20import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
21import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
22import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
23
24import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
25import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS;
26import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS;
27import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY;
28import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME;
29import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS;
30
31import static org.junit.Assert.assertEquals;
32import static org.junit.Assert.assertFalse;
33import static org.junit.Assert.assertTrue;
34import static org.mockito.ArgumentMatchers.any;
35import static org.mockito.ArgumentMatchers.anyInt;
36import static org.mockito.ArgumentMatchers.eq;
37import static org.mockito.Mockito.doReturn;
38import static org.mockito.Mockito.mock;
39import static org.mockito.Mockito.times;
40import static org.mockito.Mockito.verify;
41
42import android.content.IntentFilter;
43import android.content.pm.ServiceInfo;
44import android.net.KeepalivePacketData;
45import android.net.LinkAddress;
46import android.net.LinkProperties;
47import android.net.NetworkCapabilities;
48import android.net.NetworkInfo;
49import android.net.NetworkUtils;
50import android.os.AsyncResult;
51import android.os.Handler;
52import android.os.HandlerThread;
53import android.os.Message;
54import android.telephony.AccessNetworkConstants.AccessNetworkType;
55import android.telephony.AccessNetworkConstants.TransportType;
56import android.telephony.CarrierConfigManager;
57import android.telephony.ServiceState;
58import android.telephony.data.DataCallResponse;
59import android.telephony.data.DataProfile;
60import android.telephony.data.DataService;
61import android.test.suitebuilder.annotation.MediumTest;
62import android.test.suitebuilder.annotation.SmallTest;
63
64import com.android.internal.R;
65import com.android.internal.telephony.PhoneConstants;
66import com.android.internal.telephony.RetryManager;
67import com.android.internal.telephony.TelephonyTest;
68import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
69import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams;
70import com.android.internal.telephony.dataconnection.DataConnection.SetupResult;
71import com.android.internal.util.IState;
72import com.android.internal.util.StateMachine;
73import com.android.server.pm.PackageManagerService;
74
75import org.junit.After;
76import org.junit.Before;
77import org.junit.Test;
78import org.mockito.ArgumentCaptor;
79import org.mockito.Mock;
80
81import java.lang.reflect.Field;
82import java.lang.reflect.Method;
83import java.util.Arrays;
84
85public class DataConnectionTest extends TelephonyTest {
86
87    @Mock
88    DcTesterFailBringUpAll mDcTesterFailBringUpAll;
89    @Mock
90    ConnectionParams mCp;
91    @Mock
92    DisconnectParams mDcp;
93    @Mock
94    ApnContext mApnContext;
95    @Mock
96    DcFailBringUp mDcFailBringUp;
97    @Mock
98    PackageManagerService mMockPackageManagerInternal;
99
100    private DataConnection mDc;
101    private DataConnectionTestHandler mDataConnectionTestHandler;
102    private DcController mDcc;
103
104    private ApnSetting mApn1 = new ApnSetting(
105            2163,                   // id
106            "44010",                // numeric
107            "sp-mode",              // name
108            "spmode.ne.jp",         // apn
109            "",                     // proxy
110            "",                     // port
111            "",                     // mmsc
112            "",                     // mmsproxy
113            "",                     // mmsport
114            "",                     // user
115            "",                     // password
116            -1,                     // authtype
117            new String[]{"default", "supl"},     // types
118            "IP",                   // protocol
119            "IP",                   // roaming_protocol
120            true,                   // carrier_enabled
121            0,                      // bearer
122            0,                      // bearer_bitmask
123            0,                      // profile_id
124            false,                  // modem_cognitive
125            0,                      // max_conns
126            0,                      // wait_time
127            0,                      // max_conns_time
128            0,                      // mtu
129            "",                     // mvno_type
130            "");                    // mnvo_match_data
131
132    private ApnSetting mApn2 = new ApnSetting(
133            2164,                   // id
134            "44010",                // numeric
135            "sp-mode",              // name
136            "spmode.ne.jp",         // apn
137            "",                     // proxy
138            "",                     // port
139            "",                     // mmsc
140            "",                     // mmsproxy
141            "",                     // mmsport
142            "",                     // user
143            "",                     // password
144            -1,                     // authtype
145            new String[]{"default", "dun"},     // types
146            "IP",                   // protocol
147            "IP",                   // roaming_protocol
148            true,                   // carrier_enabled
149            0,                      // bearer
150            0,                      // bearer_bitmask
151            0,                      // profile_id
152            false,                  // modem_cognitive
153            0,                      // max_conns
154            0,                      // wait_time
155            0,                      // max_conns_time
156            0,                      // mtu
157            "",                     // mvno_type
158            "");                    // mnvo_match_data
159
160    private class DataConnectionTestHandler extends HandlerThread {
161
162        private DataConnectionTestHandler(String name) {
163            super(name);
164        }
165
166        @Override
167        public void onLooperPrepared() {
168            Handler h = new Handler();
169
170            DataServiceManager manager = new DataServiceManager(mPhone, TransportType.WWAN);
171            mDcc = DcController.makeDcc(mPhone, mDcTracker, manager, h);
172            mDcc.start();
173            mDc = DataConnection.makeDataConnection(mPhone, 0, mDcTracker, manager,
174                    mDcTesterFailBringUpAll, mDcc);
175        }
176    }
177
178    private void addDataService() {
179        CellularDataService cellularDataService = new CellularDataService();
180        ServiceInfo serviceInfo = new ServiceInfo();
181        serviceInfo.packageName = "com.android.phone";
182        serviceInfo.permission = "android.permission.BIND_DATA_SERVICE";
183        IntentFilter filter = new IntentFilter();
184        mContextFixture.addService(
185                DataService.DATA_SERVICE_INTERFACE,
186                null,
187                "com.android.phone",
188                cellularDataService.mBinder,
189                serviceInfo,
190                filter);
191    }
192
193
194    @Before
195    public void setUp() throws Exception {
196        logd("+Setup!");
197        super.setUp(getClass().getSimpleName());
198        mServiceManagerMockedServices.put("package", mMockPackageManagerInternal);
199        doReturn("fake.action_detached").when(mPhone).getActionDetached();
200        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext);
201        replaceInstance(ConnectionParams.class, "mRilRat", mCp,
202                ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
203        doReturn(mApn1).when(mApnContext).getApnSetting();
204        doReturn(PhoneConstants.APN_TYPE_DEFAULT).when(mApnContext).getApnType();
205        doReturn(true).when(mDcTracker).isDataEnabled();
206
207        mDcFailBringUp.saveParameters(0, 0, -2);
208        doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp();
209
210        mContextFixture.putStringArrayResource(com.android.internal.R.array.
211                config_mobile_tcp_buffers, new String[]{
212                "umts:131072,262144,1452032,4096,16384,399360",
213                "hspa:131072,262144,2441216,4096,16384,399360",
214                "hsupa:131072,262144,2441216,4096,16384,399360",
215                "hsdpa:131072,262144,2441216,4096,16384,399360",
216                "hspap:131072,262144,2441216,4096,16384,399360",
217                "edge:16384,32768,131072,4096,16384,65536",
218                "gprs:4096,8192,24576,4096,8192,24576",
219                "1xrtt:16384,32768,131070,4096,16384,102400",
220                "evdo:131072,262144,1048576,4096,16384,524288",
221                "lte:524288,1048576,8388608,262144,524288,4194304"});
222
223        mContextFixture.putResource(R.string.config_wwan_data_service_package,
224                "com.android.phone");
225
226        mDcp.mApnContext = mApnContext;
227
228        addDataService();
229
230        mDataConnectionTestHandler = new DataConnectionTestHandler(getClass().getSimpleName());
231        mDataConnectionTestHandler.start();
232
233        waitForMs(200);
234        logd("-Setup!");
235    }
236
237    @After
238    public void tearDown() throws Exception {
239        logd("tearDown");
240        mDc = null;
241        mDcc = null;
242        mDataConnectionTestHandler.quit();
243        super.tearDown();
244    }
245
246    private IState getCurrentState() throws Exception {
247        Method method = StateMachine.class.getDeclaredMethod("getCurrentState");
248        method.setAccessible(true);
249        return (IState) method.invoke(mDc);
250    }
251
252    private long getSuggestedRetryDelay(DataCallResponse response) throws Exception {
253        Class[] cArgs = new Class[1];
254        cArgs[0] = DataCallResponse.class;
255        Method method = DataConnection.class.getDeclaredMethod("getSuggestedRetryDelay", cArgs);
256        method.setAccessible(true);
257        return (long) method.invoke(mDc, response);
258    }
259
260    private SetupResult setLinkProperties(DataCallResponse response,
261                                                         LinkProperties linkProperties)
262            throws Exception {
263        Class[] cArgs = new Class[2];
264        cArgs[0] = DataCallResponse.class;
265        cArgs[1] = LinkProperties.class;
266        Method method = DataConnection.class.getDeclaredMethod("setLinkProperties", cArgs);
267        method.setAccessible(true);
268        return (SetupResult) method.invoke(mDc, response, linkProperties);
269    }
270
271    @Test
272    @SmallTest
273    public void testSanity() throws Exception {
274        assertEquals("DcInactiveState", getCurrentState().getName());
275    }
276
277    @Test
278    @SmallTest
279    public void testConnectEvent() throws Exception {
280        testSanity();
281
282        mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
283        waitForMs(200);
284
285        verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class),
286                eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null));
287        verify(mCT, times(1)).registerForVoiceCallEnded(any(Handler.class),
288                eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED), eq(null));
289        verify(mSimulatedCommandsVerifier, times(1))
290                .registerForNattKeepaliveStatus(any(Handler.class),
291                        eq(DataConnection.EVENT_KEEPALIVE_STATUS), eq(null));
292        verify(mSimulatedCommandsVerifier, times(1))
293                .registerForLceInfo(any(Handler.class),
294                        eq(DataConnection.EVENT_LINK_CAPACITY_CHANGED), eq(null));
295
296        ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
297        verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
298                eq(AccessNetworkType.UTRAN), dpCaptor.capture(), eq(false),
299                eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), any(Message.class));
300
301        assertEquals("spmode.ne.jp", dpCaptor.getValue().getApn());
302
303        assertEquals("DcActiveState", getCurrentState().getName());
304    }
305
306    @Test
307    @SmallTest
308    public void testDisconnectEvent() throws Exception {
309        testConnectEvent();
310
311        mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp);
312        waitForMs(100);
313
314        verify(mSimulatedCommandsVerifier, times(1)).unregisterForLceInfo(any(Handler.class));
315        verify(mSimulatedCommandsVerifier, times(1))
316                .unregisterForNattKeepaliveStatus(any(Handler.class));
317        verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(eq(1),
318                eq(DataService.REQUEST_REASON_NORMAL), any(Message.class));
319
320        assertEquals("DcInactiveState", getCurrentState().getName());
321    }
322
323    @Test
324    @SmallTest
325    public void testModemSuggestRetry() throws Exception {
326        DataCallResponse response = new DataCallResponse(0, 0, 1, 2, "IP", FAKE_IFNAME,
327                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
328                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
329                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
330                Arrays.asList(FAKE_PCSCF_ADDRESS),
331                1440);
332
333        assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response));
334
335        response = new DataCallResponse(0, 1000, 1, 2, "IP", FAKE_IFNAME,
336                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
337                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
338                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
339                Arrays.asList(FAKE_PCSCF_ADDRESS),
340                1440);
341        assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response));
342
343        response = new DataCallResponse(0, 9999, 1, 2, "IP", FAKE_IFNAME,
344                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
345                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
346                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
347                Arrays.asList(FAKE_PCSCF_ADDRESS),
348                1440);
349        assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response));
350    }
351
352    @Test
353    @SmallTest
354    public void testModemNotSuggestRetry() throws Exception {
355        DataCallResponse response = new DataCallResponse(0, -1, 1, 2, "IP", FAKE_IFNAME,
356                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
357                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
358                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
359                Arrays.asList(FAKE_PCSCF_ADDRESS),
360                1440);
361
362        assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response));
363
364        response = new DataCallResponse(0, -5, 1, 2, "IP", FAKE_IFNAME,
365                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
366                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
367                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
368                Arrays.asList(FAKE_PCSCF_ADDRESS),
369                1440);
370        assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response));
371
372        response = new DataCallResponse(0, Integer.MIN_VALUE, 1, 2, "IP", FAKE_IFNAME,
373                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
374                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
375                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
376                Arrays.asList(FAKE_PCSCF_ADDRESS),
377                1440);
378        assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response));
379    }
380
381    @Test
382    @SmallTest
383    public void testModemSuggestNoRetry() throws Exception {
384        DataCallResponse response = new DataCallResponse(0, Integer.MAX_VALUE, 1, 2, "IP",
385                FAKE_IFNAME,
386                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
387                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
388                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
389                Arrays.asList(FAKE_PCSCF_ADDRESS),
390                1440);
391        assertEquals(RetryManager.NO_RETRY, getSuggestedRetryDelay(response));
392    }
393
394    private NetworkInfo getNetworkInfo() throws Exception {
395        Field f = DataConnection.class.getDeclaredField("mNetworkInfo");
396        f.setAccessible(true);
397        return (NetworkInfo) f.get(mDc);
398    }
399
400    private NetworkCapabilities getNetworkCapabilities() throws Exception {
401        Method method = DataConnection.class.getDeclaredMethod("getNetworkCapabilities");
402        method.setAccessible(true);
403        return (NetworkCapabilities) method.invoke(mDc);
404    }
405
406    @Test
407    @SmallTest
408    public void testNetworkCapability() throws Exception {
409        mContextFixture.getCarrierConfigBundle().putStringArray(
410                CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
411                new String[] { "default" });
412        doReturn(mApn2).when(mApnContext).getApnSetting();
413        testConnectEvent();
414
415        assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
416                .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN));
417        assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
418                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
419        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
420                .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS));
421
422        mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp);
423        waitForMs(100);
424        doReturn(mApn1).when(mApnContext).getApnSetting();
425        mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
426        waitForMs(200);
427
428        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
429                .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN));
430        assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
431                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
432        assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
433                .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL));
434    }
435
436    @Test
437    @SmallTest
438    public void testMeteredCapability() throws Exception {
439
440        mContextFixture.getCarrierConfigBundle().
441                putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
442                new String[] {"default"});
443
444        testConnectEvent();
445
446        assertFalse(getNetworkCapabilities()
447                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
448    }
449
450    @Test
451    @SmallTest
452    public void testNonMeteredCapability() throws Exception {
453
454        doReturn(2819).when(mPhone).getSubId();
455        mContextFixture.getCarrierConfigBundle().
456                putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
457                        new String[] {"mms"});
458
459        testConnectEvent();
460
461        assertTrue(getNetworkCapabilities()
462                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
463    }
464
465    @Test
466    public void testOverrideUnmetered() throws Exception {
467        mContextFixture.getCarrierConfigBundle().putStringArray(
468                CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
469                new String[] { "default" });
470        testConnectEvent();
471
472        assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
473        assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
474
475        mDc.onSubscriptionOverride(OVERRIDE_UNMETERED, OVERRIDE_UNMETERED);
476
477        assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
478        assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
479
480        mDc.onSubscriptionOverride(OVERRIDE_UNMETERED, 0);
481
482        assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
483        assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
484    }
485
486    @Test
487    public void testOverrideCongested() throws Exception {
488        mContextFixture.getCarrierConfigBundle().putStringArray(
489                CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
490                new String[] { "default" });
491        testConnectEvent();
492
493        assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
494        assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
495
496        mDc.onSubscriptionOverride(OVERRIDE_CONGESTED, OVERRIDE_CONGESTED);
497
498        assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
499        assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
500
501        mDc.onSubscriptionOverride(OVERRIDE_CONGESTED, 0);
502
503        assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
504        assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
505    }
506
507    @SmallTest
508    public void testIsIpAddress() throws Exception {
509        // IPv4
510        assertTrue(DataConnection.isIpAddress("1.2.3.4"));
511        assertTrue(DataConnection.isIpAddress("127.0.0.1"));
512
513        // IPv6
514        assertTrue(DataConnection.isIpAddress("::1"));
515        assertTrue(DataConnection.isIpAddress("2001:4860:800d::68"));
516    }
517
518    @Test
519    @SmallTest
520    public void testSetLinkProperties() throws Exception {
521
522        DataCallResponse response = new DataCallResponse(0, -1, 1, 2, "IP", FAKE_IFNAME,
523                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
524                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
525                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
526                Arrays.asList(FAKE_PCSCF_ADDRESS),
527                1440);
528
529        LinkProperties linkProperties = new LinkProperties();
530        assertEquals(SetupResult.SUCCESS, setLinkProperties(response, linkProperties));
531        logd(linkProperties.toString());
532        assertEquals(response.getIfname(), linkProperties.getInterfaceName());
533        assertEquals(response.getAddresses().size(), linkProperties.getAddresses().size());
534        for (int i = 0; i < response.getAddresses().size(); ++i) {
535            assertEquals(response.getAddresses().get(i).getAddress(),
536                    NetworkUtils.numericToInetAddress(linkProperties.getLinkAddresses().get(i)
537                            .getAddress().getHostAddress()));
538        }
539
540        assertEquals(response.getDnses().size(), linkProperties.getDnsServers().size());
541        for (int i = 0; i < response.getDnses().size(); ++i) {
542            assertEquals("i = " + i, response.getDnses().get(i), NetworkUtils.numericToInetAddress(
543                    linkProperties.getDnsServers().get(i).getHostAddress()));
544        }
545
546        assertEquals(response.getGateways().size(), linkProperties.getRoutes().size());
547        for (int i = 0; i < response.getGateways().size(); ++i) {
548            assertEquals("i = " + i, response.getGateways().get(i),
549                    NetworkUtils.numericToInetAddress(linkProperties.getRoutes().get(i)
550                            .getGateway().getHostAddress()));
551        }
552
553        assertEquals(response.getMtu(), linkProperties.getMtu());
554    }
555
556    @Test
557    @SmallTest
558    public void testSetLinkPropertiesEmptyAddress() throws Exception {
559
560        // 224.224.224.224 is an invalid address.
561        DataCallResponse response = new DataCallResponse(0, -1, 1, 2, "IP", FAKE_IFNAME,
562                null,
563                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
564                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
565                Arrays.asList(FAKE_PCSCF_ADDRESS),
566                1440);
567
568        LinkProperties linkProperties = new LinkProperties();
569        assertEquals(SetupResult.ERROR_INVALID_ARG,
570                setLinkProperties(response, linkProperties));
571    }
572
573    @Test
574    @SmallTest
575    public void testSetLinkPropertiesEmptyDns() throws Exception {
576
577        // Empty dns entry.
578        DataCallResponse response = new DataCallResponse(0, -1, 1, 2, "IP", FAKE_IFNAME,
579                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
580                null,
581                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
582                Arrays.asList(FAKE_PCSCF_ADDRESS),
583                1440);
584
585        // Make sure no exception was thrown
586        LinkProperties linkProperties = new LinkProperties();
587        assertEquals(SetupResult.SUCCESS, setLinkProperties(response, linkProperties));
588    }
589
590    @Test
591    @SmallTest
592    public void testStartKeepaliveWLAN() throws Exception {
593        testConnectEvent();
594        waitForMs(200);
595
596        DataServiceManager mockDsm = mock(DataServiceManager.class);
597        doReturn(TransportType.WLAN).when(mockDsm).getTransportType();
598        replaceInstance(DataConnection.class, "mDataServiceManager", mDc, mockDsm);
599
600        final int sessionHandle = 0xF00;
601        final int slotId = 3;
602        final int interval = 10; // seconds
603        // Construct a new KeepalivePacketData request as we would receive from a Network Agent,
604        // and check that the packet is sent to the RIL.
605        KeepalivePacketData kd = KeepalivePacketData.nattKeepalivePacket(
606                NetworkUtils.numericToInetAddress("1.2.3.4"),
607                1234,
608                NetworkUtils.numericToInetAddress("8.8.8.8"),
609                4500);
610        mDc.obtainMessage(
611                DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget();
612        waitForMs(100);
613        // testStartStopNattKeepalive() verifies that this request is passed with WWAN.
614        // Thus, even though we can't see the response in NetworkAgent, we can verify that the
615        // CommandsInterface never receives a request and infer that it was dropped due to WLAN.
616        verify(mSimulatedCommandsVerifier, times(0))
617                .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class));
618    }
619
620    public void checkStartStopNattKeepalive(boolean useCondensedFlow) throws Exception {
621        testConnectEvent();
622        waitForMs(200);
623
624        final int sessionHandle = 0xF00;
625        final int slotId = 3;
626        final int interval = 10; // seconds
627        // Construct a new KeepalivePacketData request as we would receive from a Network Agent,
628        // and check that the packet is sent to the RIL.
629        KeepalivePacketData kd = KeepalivePacketData.nattKeepalivePacket(
630                NetworkUtils.numericToInetAddress("1.2.3.4"),
631                1234,
632                NetworkUtils.numericToInetAddress("8.8.8.8"),
633                4500);
634        mDc.obtainMessage(
635                DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget();
636        waitForMs(100);
637        verify(mSimulatedCommandsVerifier, times(1))
638                .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class));
639
640        Message kaStarted = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STARTED, slotId, 0);
641        if (useCondensedFlow) {
642            // Send a singled condensed response that a keepalive have been requested and the
643            // activation is completed. This flow should be used if the keepalive offload request
644            // is handled by a high-priority signalling path.
645            AsyncResult.forMessage(
646                    kaStarted, new KeepaliveStatus(
647                            sessionHandle, KeepaliveStatus.STATUS_ACTIVE), null);
648            kaStarted.sendToTarget();
649        } else {
650            // Send the sequential responses indicating first that the request was received and
651            // then that the keepalive is running. This should create an active record of the
652            // keepalive in DataConnection while permitting the status from a low priority or other
653            // high-latency handler to activate the keepalive without blocking a request.
654            AsyncResult.forMessage(
655                    kaStarted, new KeepaliveStatus(
656                            sessionHandle, KeepaliveStatus.STATUS_PENDING), null);
657            kaStarted.sendToTarget();
658            Message kaRunning = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STATUS);
659            AsyncResult.forMessage(
660                    kaRunning, new KeepaliveStatus(
661                            sessionHandle, KeepaliveStatus.STATUS_ACTIVE), null);
662            kaRunning.sendToTarget();
663        }
664        waitForMs(100);
665
666        // Verify that we can stop the connection, which checks that the record in DataConnection
667        // has a valid mapping between slotId (from network agent) to sessionHandle (from Radio).
668        mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget();
669        waitForMs(100);
670        verify(mSimulatedCommandsVerifier, times(1))
671                .stopNattKeepalive(eq(sessionHandle), any(Message.class));
672
673        Message kaStopped = mDc.obtainMessage(
674                DataConnection.EVENT_KEEPALIVE_STOPPED, sessionHandle, slotId);
675        AsyncResult.forMessage(kaStopped);
676        kaStopped.sendToTarget();
677        // Verify that after the connection is stopped, the mapping for a Keepalive Session is
678        // removed. Thus, subsequent calls to stop the same keepalive are ignored.
679        mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget();
680        waitForMs(100);
681        // Check that the mock has not been called subsequent to the previous invocation
682        // while avoiding the use of reset()
683        verify(mSimulatedCommandsVerifier, times(1))
684                .stopNattKeepalive(anyInt(), any(Message.class));
685    }
686
687    @Test
688    @MediumTest
689    public void testStartStopNattKeepalive() throws Exception {
690        checkStartStopNattKeepalive(false);
691    }
692
693    @Test
694    @MediumTest
695    public void testStartStopNattKeepaliveCondensed() throws Exception {
696        checkStartStopNattKeepalive(true);
697    }
698
699    public void checkStartNattKeepaliveFail(boolean useCondensedFlow) throws Exception {
700        testConnectEvent();
701        waitForMs(200);
702
703        final int sessionHandle = 0xF00;
704        final int slotId = 3;
705        final int interval = 10; // seconds
706        // Construct a new KeepalivePacketData request as we would receive from a Network Agent,
707        // and check that the packet is sent to the RIL.
708        KeepalivePacketData kd = KeepalivePacketData.nattKeepalivePacket(
709                NetworkUtils.numericToInetAddress("1.2.3.4"),
710                1234,
711                NetworkUtils.numericToInetAddress("8.8.8.8"),
712                4500);
713        mDc.obtainMessage(
714                DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget();
715        waitForMs(100);
716        verify(mSimulatedCommandsVerifier, times(1))
717                .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class));
718
719        Message kaStarted = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STARTED, slotId, 0);
720        if (useCondensedFlow) {
721            // Indicate in the response that the keepalive has failed.
722            AsyncResult.forMessage(
723                    kaStarted, new KeepaliveStatus(KeepaliveStatus.ERROR_UNSUPPORTED), null);
724            kaStarted.sendToTarget();
725        } else {
726            // Indicate that the keepalive is queued, and then signal a failure from the modem
727            // such that a pending keepalive fails to activate.
728            AsyncResult.forMessage(
729                    kaStarted, new KeepaliveStatus(
730                            sessionHandle, KeepaliveStatus.STATUS_PENDING), null);
731            kaStarted.sendToTarget();
732            Message kaRunning = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STATUS);
733            AsyncResult.forMessage(
734                    kaRunning, new KeepaliveStatus(
735                            sessionHandle, KeepaliveStatus.STATUS_INACTIVE), null);
736            kaRunning.sendToTarget();
737        }
738        waitForMs(100);
739        // Verify that a failed connection request cannot be stopped due to no record in
740        // the DataConnection.
741        mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget();
742        waitForMs(100);
743        verify(mSimulatedCommandsVerifier, times(0))
744                .stopNattKeepalive(anyInt(), any(Message.class));
745    }
746
747    @Test
748    @SmallTest
749    public void testStartNattKeepaliveFail() throws Exception {
750        checkStartNattKeepaliveFail(false);
751    }
752
753    @Test
754    @SmallTest
755    public void testStartNattKeepaliveFailCondensed() throws Exception {
756        checkStartNattKeepaliveFail(true);
757    }
758}
759