1 /*
2  * Copyright (C) 2017 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 android.net;
18 
19 import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
20 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
21 import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
22 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
23 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
24 import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
25 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
26 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
27 import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
28 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
29 import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
30 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
31 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
32 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
33 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
34 
35 import static org.junit.Assert.assertFalse;
36 import static org.junit.Assert.assertNotNull;
37 import static org.junit.Assert.assertNull;
38 import static org.junit.Assert.assertTrue;
39 import static org.junit.Assert.fail;
40 import static org.mockito.Mockito.any;
41 import static org.mockito.Mockito.anyBoolean;
42 import static org.mockito.Mockito.anyInt;
43 import static org.mockito.Mockito.mock;
44 import static org.mockito.Mockito.timeout;
45 import static org.mockito.Mockito.times;
46 import static org.mockito.Mockito.verify;
47 import static org.mockito.Mockito.when;
48 
49 import android.app.PendingIntent;
50 import android.net.ConnectivityManager;
51 import android.net.NetworkCapabilities;
52 import android.content.Context;
53 import android.os.Bundle;
54 import android.os.Handler;
55 import android.os.Looper;
56 import android.os.Message;
57 import android.os.Messenger;
58 import android.content.pm.ApplicationInfo;
59 import android.os.Build.VERSION_CODES;
60 import android.net.ConnectivityManager.NetworkCallback;
61 import android.support.test.filters.SmallTest;
62 import android.support.test.runner.AndroidJUnit4;
63 
64 import org.junit.Before;
65 import org.junit.Test;
66 import org.junit.runner.RunWith;
67 import org.mockito.ArgumentCaptor;
68 import org.mockito.Mock;
69 import org.mockito.MockitoAnnotations;
70 
71 @RunWith(AndroidJUnit4.class)
72 @SmallTest
73 public class ConnectivityManagerTest {
74 
75     @Mock Context mCtx;
76     @Mock IConnectivityManager mService;
77 
78     @Before
setUp()79     public void setUp() {
80         MockitoAnnotations.initMocks(this);
81     }
82 
verifyNetworkCapabilities( int legacyType, int transportType, int... capabilities)83     static NetworkCapabilities verifyNetworkCapabilities(
84             int legacyType, int transportType, int... capabilities) {
85         final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
86         assertNotNull(nc);
87         assertTrue(nc.hasTransport(transportType));
88         for (int capability : capabilities) {
89             assertTrue(nc.hasCapability(capability));
90         }
91 
92         return nc;
93     }
94 
verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType)95     static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) {
96         verifyNetworkCapabilities(
97                 legacyType,
98                 transportType,
99                 NET_CAPABILITY_INTERNET,
100                 NET_CAPABILITY_NOT_RESTRICTED,
101                 NET_CAPABILITY_NOT_VPN,
102                 NET_CAPABILITY_TRUSTED);
103     }
104 
verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability)105     static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) {
106         final NetworkCapabilities nc = verifyNetworkCapabilities(
107                 legacyType,
108                 TRANSPORT_CELLULAR,
109                 capability,
110                 NET_CAPABILITY_NOT_VPN,
111                 NET_CAPABILITY_TRUSTED);
112 
113         assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
114         assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
115     }
116 
117     @Test
testNetworkCapabilitiesForTypeMobile()118     public void testNetworkCapabilitiesForTypeMobile() {
119         verifyUnrestrictedNetworkCapabilities(
120                 ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR);
121     }
122 
123     @Test
testNetworkCapabilitiesForTypeMobileCbs()124     public void testNetworkCapabilitiesForTypeMobileCbs() {
125         verifyRestrictedMobileNetworkCapabilities(
126                 ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS);
127     }
128 
129     @Test
testNetworkCapabilitiesForTypeMobileDun()130     public void testNetworkCapabilitiesForTypeMobileDun() {
131         verifyRestrictedMobileNetworkCapabilities(
132                 ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN);
133     }
134 
135     @Test
testNetworkCapabilitiesForTypeMobileFota()136     public void testNetworkCapabilitiesForTypeMobileFota() {
137         verifyRestrictedMobileNetworkCapabilities(
138                 ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA);
139     }
140 
141     @Test
testNetworkCapabilitiesForTypeMobileHipri()142     public void testNetworkCapabilitiesForTypeMobileHipri() {
143         verifyUnrestrictedNetworkCapabilities(
144                 ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR);
145     }
146 
147     @Test
testNetworkCapabilitiesForTypeMobileIms()148     public void testNetworkCapabilitiesForTypeMobileIms() {
149         verifyRestrictedMobileNetworkCapabilities(
150                 ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS);
151     }
152 
153     @Test
testNetworkCapabilitiesForTypeMobileMms()154     public void testNetworkCapabilitiesForTypeMobileMms() {
155         final NetworkCapabilities nc = verifyNetworkCapabilities(
156                 ConnectivityManager.TYPE_MOBILE_MMS,
157                 TRANSPORT_CELLULAR,
158                 NET_CAPABILITY_MMS,
159                 NET_CAPABILITY_NOT_VPN,
160                 NET_CAPABILITY_TRUSTED);
161 
162         assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
163     }
164 
165     @Test
testNetworkCapabilitiesForTypeMobileSupl()166     public void testNetworkCapabilitiesForTypeMobileSupl() {
167         final NetworkCapabilities nc = verifyNetworkCapabilities(
168                 ConnectivityManager.TYPE_MOBILE_SUPL,
169                 TRANSPORT_CELLULAR,
170                 NET_CAPABILITY_SUPL,
171                 NET_CAPABILITY_NOT_VPN,
172                 NET_CAPABILITY_TRUSTED);
173 
174         assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
175     }
176 
177     @Test
testNetworkCapabilitiesForTypeWifi()178     public void testNetworkCapabilitiesForTypeWifi() {
179         verifyUnrestrictedNetworkCapabilities(
180                 ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI);
181     }
182 
183     @Test
testNetworkCapabilitiesForTypeWifiP2p()184     public void testNetworkCapabilitiesForTypeWifiP2p() {
185         final NetworkCapabilities nc = verifyNetworkCapabilities(
186                 ConnectivityManager.TYPE_WIFI_P2P,
187                 TRANSPORT_WIFI,
188                 NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN,
189                 NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P);
190 
191         assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
192     }
193 
194     @Test
testNetworkCapabilitiesForTypeBluetooth()195     public void testNetworkCapabilitiesForTypeBluetooth() {
196         verifyUnrestrictedNetworkCapabilities(
197                 ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH);
198     }
199 
200     @Test
testNetworkCapabilitiesForTypeEthernet()201     public void testNetworkCapabilitiesForTypeEthernet() {
202         verifyUnrestrictedNetworkCapabilities(
203                 ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET);
204     }
205 
206     @Test
testCallbackRelease()207     public void testCallbackRelease() throws Exception {
208         ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
209         NetworkRequest request = makeRequest(1);
210         NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
211         Handler handler = new Handler(Looper.getMainLooper());
212         ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
213 
214         // register callback
215         when(mService.requestNetwork(any(), captor.capture(), anyInt(), any(), anyInt()))
216                 .thenReturn(request);
217         manager.requestNetwork(request, callback, handler);
218 
219         // callback triggers
220         captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE));
221         verify(callback, timeout(500).times(1)).onAvailable(any(Network.class),
222                 any(NetworkCapabilities.class), any(LinkProperties.class));
223 
224         // unregister callback
225         manager.unregisterNetworkCallback(callback);
226         verify(mService, times(1)).releaseNetworkRequest(request);
227 
228         // callback does not trigger anymore.
229         captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_LOSING));
230         verify(callback, timeout(500).times(0)).onLosing(any(), anyInt());
231     }
232 
233     @Test
testCallbackRecycling()234     public void testCallbackRecycling() throws Exception {
235         ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
236         NetworkRequest req1 = makeRequest(1);
237         NetworkRequest req2 = makeRequest(2);
238         NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
239         Handler handler = new Handler(Looper.getMainLooper());
240         ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
241 
242         // register callback
243         when(mService.requestNetwork(any(), captor.capture(), anyInt(), any(), anyInt()))
244                 .thenReturn(req1);
245         manager.requestNetwork(req1, callback, handler);
246 
247         // callback triggers
248         captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE));
249         verify(callback, timeout(100).times(1)).onAvailable(any(Network.class),
250                 any(NetworkCapabilities.class), any(LinkProperties.class));
251 
252         // unregister callback
253         manager.unregisterNetworkCallback(callback);
254         verify(mService, times(1)).releaseNetworkRequest(req1);
255 
256         // callback does not trigger anymore.
257         captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_LOSING));
258         verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
259 
260         // callback can be registered again
261         when(mService.requestNetwork(any(), captor.capture(), anyInt(), any(), anyInt()))
262                 .thenReturn(req2);
263         manager.requestNetwork(req2, callback, handler);
264 
265         // callback triggers
266         captor.getValue().send(makeMessage(req2, ConnectivityManager.CALLBACK_LOST));
267         verify(callback, timeout(100).times(1)).onLost(any());
268 
269         // unregister callback
270         manager.unregisterNetworkCallback(callback);
271         verify(mService, times(1)).releaseNetworkRequest(req2);
272     }
273 
274     // TODO: turn on this test when request  callback 1:1 mapping is enforced
275     //@Test
noDoubleCallbackRegistration()276     private void noDoubleCallbackRegistration() throws Exception {
277         ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
278         NetworkRequest request = makeRequest(1);
279         NetworkCallback callback = new ConnectivityManager.NetworkCallback();
280         ApplicationInfo info = new ApplicationInfo();
281         // TODO: update version when starting to enforce 1:1 mapping
282         info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
283 
284         when(mCtx.getApplicationInfo()).thenReturn(info);
285         when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt())).thenReturn(request);
286 
287         Handler handler = new Handler(Looper.getMainLooper());
288         manager.requestNetwork(request, callback, handler);
289 
290         // callback is already registered, reregistration should fail.
291         Class<IllegalArgumentException> wantException = IllegalArgumentException.class;
292         expectThrowable(() -> manager.requestNetwork(request, callback), wantException);
293 
294         manager.unregisterNetworkCallback(callback);
295         verify(mService, times(1)).releaseNetworkRequest(request);
296 
297         // unregistering the callback should make it registrable again.
298         manager.requestNetwork(request, callback);
299     }
300 
301     @Test
testArgumentValidation()302     public void testArgumentValidation() throws Exception {
303         ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
304 
305         NetworkRequest request = mock(NetworkRequest.class);
306         NetworkCallback callback = mock(NetworkCallback.class);
307         Handler handler = mock(Handler.class);
308         NetworkCallback nullCallback = null;
309         PendingIntent nullIntent = null;
310 
311         mustFail(() -> { manager.requestNetwork(null, callback); });
312         mustFail(() -> { manager.requestNetwork(request, nullCallback); });
313         mustFail(() -> { manager.requestNetwork(request, callback, null); });
314         mustFail(() -> { manager.requestNetwork(request, callback, -1); });
315         mustFail(() -> { manager.requestNetwork(request, nullIntent); });
316 
317         mustFail(() -> { manager.registerNetworkCallback(null, callback, handler); });
318         mustFail(() -> { manager.registerNetworkCallback(request, null, handler); });
319         mustFail(() -> { manager.registerNetworkCallback(request, callback, null); });
320         mustFail(() -> { manager.registerNetworkCallback(request, nullIntent); });
321 
322         mustFail(() -> { manager.registerDefaultNetworkCallback(null, handler); });
323         mustFail(() -> { manager.registerDefaultNetworkCallback(callback, null); });
324 
325         mustFail(() -> { manager.unregisterNetworkCallback(nullCallback); });
326         mustFail(() -> { manager.unregisterNetworkCallback(nullIntent); });
327         mustFail(() -> { manager.releaseNetworkRequest(nullIntent); });
328     }
329 
mustFail(Runnable fn)330     static void mustFail(Runnable fn) {
331         try {
332             fn.run();
333             fail();
334         } catch (Exception expected) {
335         }
336     }
337 
makeMessage(NetworkRequest req, int messageType)338     static Message makeMessage(NetworkRequest req, int messageType) {
339         Bundle bundle = new Bundle();
340         bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
341         // Pass default objects as we don't care which get passed here
342         bundle.putParcelable(Network.class.getSimpleName(), new Network(1));
343         bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities());
344         bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties());
345         Message msg = Message.obtain();
346         msg.what = messageType;
347         msg.setData(bundle);
348         return msg;
349     }
350 
makeRequest(int requestId)351     static NetworkRequest makeRequest(int requestId) {
352         NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
353         return new NetworkRequest(request.networkCapabilities, ConnectivityManager.TYPE_NONE,
354                 requestId, NetworkRequest.Type.NONE);
355     }
356 
expectThrowable(Runnable block, Class<? extends Throwable> throwableType)357     static void expectThrowable(Runnable block, Class<? extends Throwable> throwableType) {
358         try {
359             block.run();
360         } catch (Throwable t) {
361             if (t.getClass().equals(throwableType)) {
362                 return;
363             }
364             fail("expected exception of type " + throwableType + ", but was " + t.getClass());
365         }
366         fail("expected exception of type " + throwableType);
367     }
368 }
369