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 com.android.internal.telephony.TelephonyTestUtils.waitForMs;
20import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS;
21import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS;
22import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY;
23import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME;
24import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS;
25
26import static org.junit.Assert.assertEquals;
27import static org.junit.Assert.assertFalse;
28import static org.junit.Assert.assertTrue;
29import static org.mockito.Matchers.any;
30import static org.mockito.Matchers.eq;
31import static org.mockito.Mockito.doReturn;
32import static org.mockito.Mockito.times;
33import static org.mockito.Mockito.verify;
34
35import android.net.NetworkCapabilities;
36import android.net.NetworkInfo;
37import android.os.AsyncResult;
38import android.os.Handler;
39import android.os.HandlerThread;
40import android.os.Message;
41import android.telephony.CarrierConfigManager;
42import android.telephony.ServiceState;
43import android.test.suitebuilder.annotation.SmallTest;
44
45import com.android.internal.telephony.PhoneConstants;
46import com.android.internal.telephony.RILConstants;
47import com.android.internal.telephony.RetryManager;
48import com.android.internal.telephony.TelephonyTest;
49import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
50import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams;
51import com.android.internal.util.IState;
52import com.android.internal.util.StateMachine;
53
54import org.junit.After;
55import org.junit.Before;
56import org.junit.Test;
57import org.mockito.ArgumentCaptor;
58import org.mockito.Mock;
59
60import java.lang.reflect.Field;
61import java.lang.reflect.Method;
62
63public class DataConnectionTest extends TelephonyTest {
64
65    @Mock
66    DcTesterFailBringUpAll mDcTesterFailBringUpAll;
67    @Mock
68    ConnectionParams mCp;
69    @Mock
70    DisconnectParams mDcp;
71    @Mock
72    ApnContext mApnContext;
73    @Mock
74    DcFailBringUp mDcFailBringUp;
75
76    private DataConnection mDc;
77    private DataConnectionTestHandler mDataConnectionTestHandler;
78    private DcController mDcc;
79
80    private ApnSetting mApn1 = new ApnSetting(
81            2163,                   // id
82            "44010",                // numeric
83            "sp-mode",              // name
84            "spmode.ne.jp",         // apn
85            "",                     // proxy
86            "",                     // port
87            "",                     // mmsc
88            "",                     // mmsproxy
89            "",                     // mmsport
90            "",                     // user
91            "",                     // password
92            -1,                     // authtype
93            new String[]{"default", "supl"},     // types
94            "IP",                   // protocol
95            "IP",                   // roaming_protocol
96            true,                   // carrier_enabled
97            0,                      // bearer
98            0,                      // bearer_bitmask
99            0,                      // profile_id
100            false,                  // modem_cognitive
101            0,                      // max_conns
102            0,                      // wait_time
103            0,                      // max_conns_time
104            0,                      // mtu
105            "",                     // mvno_type
106            "");                    // mnvo_match_data
107
108    private class DataConnectionTestHandler extends HandlerThread {
109
110        private DataConnectionTestHandler(String name) {
111            super(name);
112        }
113
114        @Override
115        public void onLooperPrepared() {
116            Handler h = new Handler();
117
118            mDcc = DcController.makeDcc(mPhone, mDcTracker, h);
119            mDc = DataConnection.makeDataConnection(mPhone, 0, mDcTracker, mDcTesterFailBringUpAll,
120                    mDcc);
121        }
122    }
123
124    @Before
125    public void setUp() throws Exception {
126        logd("+Setup!");
127        super.setUp(getClass().getSimpleName());
128
129        doReturn("fake.action_detached").when(mPhone).getActionDetached();
130        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext);
131        replaceInstance(ConnectionParams.class, "mRilRat", mCp,
132                ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
133        doReturn(mApn1).when(mApnContext).getApnSetting();
134        doReturn(PhoneConstants.APN_TYPE_DEFAULT).when(mApnContext).getApnType();
135
136        mDcFailBringUp.saveParameters(0, 0, -2);
137        doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp();
138
139        mContextFixture.putStringArrayResource(com.android.internal.R.array.
140                config_mobile_tcp_buffers, new String[]{
141                "umts:131072,262144,1452032,4096,16384,399360",
142                "hspa:131072,262144,2441216,4096,16384,399360",
143                "hsupa:131072,262144,2441216,4096,16384,399360",
144                "hsdpa:131072,262144,2441216,4096,16384,399360",
145                "hspap:131072,262144,2441216,4096,16384,399360",
146                "edge:16384,32768,131072,4096,16384,65536",
147                "gprs:4096,8192,24576,4096,8192,24576",
148                "1xrtt:16384,32768,131070,4096,16384,102400",
149                "evdo:131072,262144,1048576,4096,16384,524288",
150                "lte:524288,1048576,8388608,262144,524288,4194304"});
151
152
153        mDcp.mApnContext = mApnContext;
154
155        mDataConnectionTestHandler = new DataConnectionTestHandler(getClass().getSimpleName());
156        mDataConnectionTestHandler.start();
157
158        waitForMs(200);
159        logd("-Setup!");
160    }
161
162    @After
163    public void tearDown() throws Exception {
164        logd("tearDown");
165        mDc = null;
166        mDcc = null;
167        mDataConnectionTestHandler.quit();
168        super.tearDown();
169    }
170
171    private IState getCurrentState() throws Exception {
172        Method method = StateMachine.class.getDeclaredMethod("getCurrentState");
173        method.setAccessible(true);
174        return (IState) method.invoke(mDc);
175    }
176
177    private long getSuggestedRetryDelay(AsyncResult ar) throws Exception {
178        Class[] cArgs = new Class[1];
179        cArgs[0] = AsyncResult.class;
180        Method method = DataConnection.class.getDeclaredMethod("getSuggestedRetryDelay", cArgs);
181        method.setAccessible(true);
182        return (long) method.invoke(mDc, ar);
183    }
184
185    @Test
186    @SmallTest
187    public void testSanity() throws Exception {
188        assertEquals("DcInactiveState", getCurrentState().getName());
189    }
190
191    @Test
192    @SmallTest
193    public void testConnectEvent() throws Exception {
194        testSanity();
195
196        mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
197        waitForMs(200);
198
199        verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class),
200                eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null));
201        verify(mCT, times(1)).registerForVoiceCallEnded(any(Handler.class),
202                eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED), eq(null));
203
204        ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
205        verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
206                eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), dpCaptor.capture(),
207                eq(false), eq(false), any(Message.class));
208
209        assertEquals("spmode.ne.jp", dpCaptor.getValue().apn);
210
211        assertEquals("DcActiveState", getCurrentState().getName());
212    }
213
214    @Test
215    @SmallTest
216    public void testDisconnectEvent() throws Exception {
217        testConnectEvent();
218
219        mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp);
220        waitForMs(100);
221
222        verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(eq(1),
223                eq(RILConstants.DEACTIVATE_REASON_NONE), any(Message.class));
224
225        assertEquals("DcInactiveState", getCurrentState().getName());
226    }
227
228    @Test
229    @SmallTest
230    public void testModemSuggestRetry() throws Exception {
231        DataCallResponse response = new DataCallResponse(0, 0, 1, 2, "IP",
232                FAKE_IFNAME, FAKE_ADDRESS, FAKE_DNS, FAKE_GATEWAY, FAKE_PCSCF_ADDRESS, 1440);
233        AsyncResult ar = new AsyncResult(null, response, null);
234        assertEquals(response.suggestedRetryTime, getSuggestedRetryDelay(ar));
235
236        response = new DataCallResponse(0, 1000, 1, 2, "IP",
237                FAKE_IFNAME, FAKE_ADDRESS, FAKE_DNS, FAKE_GATEWAY, FAKE_PCSCF_ADDRESS, 1440);
238        ar = new AsyncResult(null, response, null);
239        assertEquals(response.suggestedRetryTime, getSuggestedRetryDelay(ar));
240
241        response = new DataCallResponse(0, 9999, 1, 2, "IP",
242                FAKE_IFNAME, FAKE_ADDRESS, FAKE_DNS, FAKE_GATEWAY, FAKE_PCSCF_ADDRESS, 1440);
243        ar = new AsyncResult(null, response, null);
244        assertEquals(response.suggestedRetryTime, getSuggestedRetryDelay(ar));
245    }
246
247    @Test
248    @SmallTest
249    public void testModemNotSuggestRetry() throws Exception {
250        DataCallResponse response = new DataCallResponse(0, -1, 1, 2, "IP", FAKE_IFNAME,
251                FAKE_ADDRESS, FAKE_DNS, FAKE_GATEWAY, FAKE_PCSCF_ADDRESS, 1440);
252        AsyncResult ar = new AsyncResult(null, response, null);
253        assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(ar));
254
255        response = new DataCallResponse(0, -5, 1, 2, "IP", FAKE_IFNAME,
256                FAKE_ADDRESS, FAKE_DNS, FAKE_GATEWAY, FAKE_PCSCF_ADDRESS, 1440);
257        ar = new AsyncResult(null, response, null);
258        assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(ar));
259
260        response = new DataCallResponse(0, Integer.MIN_VALUE, 1, 2, "IP", FAKE_IFNAME,
261                FAKE_ADDRESS, FAKE_DNS, FAKE_GATEWAY, FAKE_PCSCF_ADDRESS, 1440);
262        ar = new AsyncResult(null, response, null);
263        assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(ar));
264    }
265
266    @Test
267    @SmallTest
268    public void testModemSuggestNoRetry() throws Exception {
269        DataCallResponse response = new DataCallResponse(0, Integer.MAX_VALUE, 1, 2, "IP",
270                FAKE_IFNAME, FAKE_ADDRESS, FAKE_DNS, FAKE_GATEWAY, FAKE_PCSCF_ADDRESS, 1440);
271        AsyncResult ar = new AsyncResult(null, response, null);
272        assertEquals(RetryManager.NO_RETRY, getSuggestedRetryDelay(ar));
273    }
274
275    private NetworkInfo getNetworkInfo() throws Exception {
276        Field f = DataConnection.class.getDeclaredField("mNetworkInfo");
277        f.setAccessible(true);
278        return (NetworkInfo) f.get(mDc);
279    }
280
281    private NetworkCapabilities getNetworkCapabilities() throws Exception {
282        Method method = DataConnection.class.getDeclaredMethod("getNetworkCapabilities");
283        method.setAccessible(true);
284        return (NetworkCapabilities) method.invoke(mDc);
285    }
286
287    @Test
288    @SmallTest
289    public void testMeteredCapability() throws Exception {
290
291        mContextFixture.getCarrierConfigBundle().
292                putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
293                new String[] {"default"});
294
295        testConnectEvent();
296
297        assertFalse(getNetworkCapabilities()
298                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
299        assertTrue(getNetworkInfo().isMetered());
300    }
301
302    @Test
303    @SmallTest
304    public void testNonMeteredCapability() throws Exception {
305
306        doReturn(2819).when(mPhone).getSubId();
307        mContextFixture.getCarrierConfigBundle().
308                putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
309                        new String[] {"mms"});
310
311        testConnectEvent();
312
313        assertTrue(getNetworkCapabilities()
314                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
315        assertFalse(getNetworkInfo().isMetered());
316    }
317}