blob: b71a46f66de7e62b39128270c47d931b88e6e769 [file] [log] [blame]
Erik Klinece55eb12017-01-26 18:08:28 +09001/*
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
17package android.net;
18
junyulaiad010792021-01-11 16:53:38 +080019import static android.net.ConnectivityManager.TYPE_NONE;
Erik Klinece55eb12017-01-26 18:08:28 +090020import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
21import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
22import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
23import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
24import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
25import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
26import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
27import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
28import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
29import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
30import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
31import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
32import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
33import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
34import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
Junyu Laia62493f2021-01-19 11:10:56 +000035import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
junyulaiad010792021-01-11 16:53:38 +080036import static android.net.NetworkRequest.Type.REQUEST;
37import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
Lorenzo Colitti76b639e2021-01-29 20:14:04 +090038import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
Erik Klinece55eb12017-01-26 18:08:28 +090039
Chiachang Wang859218c2021-09-16 14:38:52 +080040import static com.android.testutils.MiscAsserts.assertThrows;
41
Erik Klinece55eb12017-01-26 18:08:28 +090042import static org.junit.Assert.assertFalse;
43import static org.junit.Assert.assertNotNull;
markchiend2015662022-04-26 18:08:03 +080044import static org.junit.Assert.assertNull;
Erik Klinece55eb12017-01-26 18:08:28 +090045import static org.junit.Assert.assertTrue;
Hugo Benichi2aa65af2017-03-06 09:17:06 +090046import static org.junit.Assert.fail;
Lorenzo Colitti79c6f222021-03-18 00:54:57 +090047import static org.mockito.ArgumentMatchers.anyBoolean;
junyulaiad010792021-01-11 16:53:38 +080048import static org.mockito.ArgumentMatchers.eq;
Philip P. Moltmann7bc33df2020-03-26 11:50:35 -070049import static org.mockito.ArgumentMatchers.nullable;
Remi NGUYEN VANc9c745f2021-06-15 16:05:56 +090050import static org.mockito.Mockito.CALLS_REAL_METHODS;
Chalard Jean1afb2e32021-10-04 16:36:32 +090051import static org.mockito.Mockito.after;
Hugo Benichi2aa65af2017-03-06 09:17:06 +090052import static org.mockito.Mockito.any;
53import static org.mockito.Mockito.anyInt;
Junyu Laic3dc5b62023-09-06 19:10:02 +080054import static org.mockito.Mockito.doReturn;
Hugo Benichi2aa65af2017-03-06 09:17:06 +090055import static org.mockito.Mockito.mock;
junyulaiad010792021-01-11 16:53:38 +080056import static org.mockito.Mockito.never;
57import static org.mockito.Mockito.reset;
Hugo Benichi2aa65af2017-03-06 09:17:06 +090058import static org.mockito.Mockito.timeout;
59import static org.mockito.Mockito.times;
60import static org.mockito.Mockito.verify;
61import static org.mockito.Mockito.when;
Erik Klinece55eb12017-01-26 18:08:28 +090062
Hugo Benichi7abd43f2017-05-09 14:09:02 +090063import android.app.PendingIntent;
Hugo Benichi2aa65af2017-03-06 09:17:06 +090064import android.content.Context;
Brett Chabot147f6cf2019-03-04 14:14:56 -080065import android.content.pm.ApplicationInfo;
Brett Chabot147f6cf2019-03-04 14:14:56 -080066import android.net.ConnectivityManager.NetworkCallback;
Brett Chabot147f6cf2019-03-04 14:14:56 -080067import android.os.Build.VERSION_CODES;
Hugo Benichi2aa65af2017-03-06 09:17:06 +090068import android.os.Bundle;
69import android.os.Handler;
70import android.os.Looper;
71import android.os.Message;
72import android.os.Messenger;
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +090073import android.os.Process;
Brett Chabot147f6cf2019-03-04 14:14:56 -080074
75import androidx.test.filters.SmallTest;
Remi NGUYEN VAN154cf1d2021-06-29 17:16:28 +090076
markchiened0fab02022-04-26 16:33:47 +080077import com.android.internal.util.test.BroadcastInterceptingContext;
Remi NGUYEN VAN154cf1d2021-06-29 17:16:28 +090078import com.android.testutils.DevSdkIgnoreRule;
79import com.android.testutils.DevSdkIgnoreRunner;
Erik Klinece55eb12017-01-26 18:08:28 +090080
Hugo Benichi2aa65af2017-03-06 09:17:06 +090081import org.junit.Before;
Junyu Lai9e880522023-11-14 15:44:37 +080082import org.junit.Rule;
Hugo Benichi1d6742c2017-03-06 06:16:51 +000083import org.junit.Test;
Hugo Benichi2aa65af2017-03-06 09:17:06 +090084import org.junit.runner.RunWith;
85import org.mockito.ArgumentCaptor;
86import org.mockito.Mock;
87import org.mockito.MockitoAnnotations;
Hugo Benichi1d6742c2017-03-06 06:16:51 +000088
markchiened0fab02022-04-26 16:33:47 +080089import java.lang.ref.WeakReference;
90
Remi NGUYEN VAN154cf1d2021-06-29 17:16:28 +090091@RunWith(DevSdkIgnoreRunner.class)
Erik Klinece55eb12017-01-26 18:08:28 +090092@SmallTest
Remi NGUYEN VAN154cf1d2021-06-29 17:16:28 +090093@DevSdkIgnoreRule.IgnoreUpTo(VERSION_CODES.R)
Erik Klinece55eb12017-01-26 18:08:28 +090094public class ConnectivityManagerTest {
Junyu Lai9e880522023-11-14 15:44:37 +080095 @Rule
96 public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
Chalard Jean1afb2e32021-10-04 16:36:32 +090097 private static final int TIMEOUT_MS = 30_000;
98 private static final int SHORT_TIMEOUT_MS = 150;
Hugo Benichi2aa65af2017-03-06 09:17:06 +090099
100 @Mock Context mCtx;
101 @Mock IConnectivityManager mService;
Junyu Laic3dc5b62023-09-06 19:10:02 +0800102 @Mock NetworkPolicyManager mNpm;
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900103
104 @Before
105 public void setUp() {
106 MockitoAnnotations.initMocks(this);
107 }
108
Erik Klinece55eb12017-01-26 18:08:28 +0900109 static NetworkCapabilities verifyNetworkCapabilities(
110 int legacyType, int transportType, int... capabilities) {
111 final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
112 assertNotNull(nc);
113 assertTrue(nc.hasTransport(transportType));
114 for (int capability : capabilities) {
115 assertTrue(nc.hasCapability(capability));
116 }
117
118 return nc;
119 }
120
121 static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) {
122 verifyNetworkCapabilities(
123 legacyType,
124 transportType,
125 NET_CAPABILITY_INTERNET,
126 NET_CAPABILITY_NOT_RESTRICTED,
127 NET_CAPABILITY_NOT_VPN,
128 NET_CAPABILITY_TRUSTED);
129 }
130
131 static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) {
132 final NetworkCapabilities nc = verifyNetworkCapabilities(
133 legacyType,
134 TRANSPORT_CELLULAR,
135 capability,
136 NET_CAPABILITY_NOT_VPN,
137 NET_CAPABILITY_TRUSTED);
138
139 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
140 assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
141 }
142
143 @Test
144 public void testNetworkCapabilitiesForTypeMobile() {
145 verifyUnrestrictedNetworkCapabilities(
146 ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR);
147 }
148
149 @Test
150 public void testNetworkCapabilitiesForTypeMobileCbs() {
151 verifyRestrictedMobileNetworkCapabilities(
152 ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS);
153 }
154
155 @Test
156 public void testNetworkCapabilitiesForTypeMobileDun() {
157 verifyRestrictedMobileNetworkCapabilities(
158 ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN);
159 }
160
161 @Test
162 public void testNetworkCapabilitiesForTypeMobileFota() {
163 verifyRestrictedMobileNetworkCapabilities(
164 ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA);
165 }
166
167 @Test
168 public void testNetworkCapabilitiesForTypeMobileHipri() {
169 verifyUnrestrictedNetworkCapabilities(
170 ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR);
171 }
172
173 @Test
174 public void testNetworkCapabilitiesForTypeMobileIms() {
175 verifyRestrictedMobileNetworkCapabilities(
176 ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS);
177 }
178
179 @Test
180 public void testNetworkCapabilitiesForTypeMobileMms() {
181 final NetworkCapabilities nc = verifyNetworkCapabilities(
182 ConnectivityManager.TYPE_MOBILE_MMS,
183 TRANSPORT_CELLULAR,
184 NET_CAPABILITY_MMS,
185 NET_CAPABILITY_NOT_VPN,
186 NET_CAPABILITY_TRUSTED);
187
188 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
189 }
190
191 @Test
192 public void testNetworkCapabilitiesForTypeMobileSupl() {
193 final NetworkCapabilities nc = verifyNetworkCapabilities(
194 ConnectivityManager.TYPE_MOBILE_SUPL,
195 TRANSPORT_CELLULAR,
196 NET_CAPABILITY_SUPL,
197 NET_CAPABILITY_NOT_VPN,
198 NET_CAPABILITY_TRUSTED);
199
200 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
201 }
202
203 @Test
204 public void testNetworkCapabilitiesForTypeWifi() {
205 verifyUnrestrictedNetworkCapabilities(
206 ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI);
207 }
208
209 @Test
210 public void testNetworkCapabilitiesForTypeWifiP2p() {
211 final NetworkCapabilities nc = verifyNetworkCapabilities(
212 ConnectivityManager.TYPE_WIFI_P2P,
213 TRANSPORT_WIFI,
214 NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN,
215 NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P);
216
217 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
218 }
219
220 @Test
221 public void testNetworkCapabilitiesForTypeBluetooth() {
222 verifyUnrestrictedNetworkCapabilities(
223 ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH);
224 }
225
226 @Test
227 public void testNetworkCapabilitiesForTypeEthernet() {
228 verifyUnrestrictedNetworkCapabilities(
229 ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET);
230 }
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900231
232 @Test
233 public void testCallbackRelease() throws Exception {
234 ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
235 NetworkRequest request = makeRequest(1);
Remi NGUYEN VANc9c745f2021-06-15 16:05:56 +0900236 NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class,
237 CALLS_REAL_METHODS);
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900238 Handler handler = new Handler(Looper.getMainLooper());
239 ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
240
241 // register callback
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900242 when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
243 anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(request);
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900244 manager.requestNetwork(request, callback, handler);
245
246 // callback triggers
247 captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE));
Chalard Jean1afb2e32021-10-04 16:36:32 +0900248 verify(callback, timeout(TIMEOUT_MS).times(1)).onAvailable(any(Network.class),
Mike Yu96612ae2018-08-17 15:22:05 +0800249 any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900250
251 // unregister callback
252 manager.unregisterNetworkCallback(callback);
253 verify(mService, times(1)).releaseNetworkRequest(request);
254
255 // callback does not trigger anymore.
256 captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_LOSING));
Chalard Jean1afb2e32021-10-04 16:36:32 +0900257 verify(callback, after(SHORT_TIMEOUT_MS).never()).onLosing(any(), anyInt());
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900258 }
259
260 @Test
261 public void testCallbackRecycling() throws Exception {
262 ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
263 NetworkRequest req1 = makeRequest(1);
264 NetworkRequest req2 = makeRequest(2);
Remi NGUYEN VANc9c745f2021-06-15 16:05:56 +0900265 NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class,
266 CALLS_REAL_METHODS);
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900267 Handler handler = new Handler(Looper.getMainLooper());
268 ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
269
270 // register callback
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900271 when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
272 anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req1);
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900273 manager.requestNetwork(req1, callback, handler);
274
275 // callback triggers
276 captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE));
Chalard Jean1afb2e32021-10-04 16:36:32 +0900277 verify(callback, timeout(TIMEOUT_MS).times(1)).onAvailable(any(Network.class),
Mike Yu96612ae2018-08-17 15:22:05 +0800278 any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900279
280 // unregister callback
281 manager.unregisterNetworkCallback(callback);
282 verify(mService, times(1)).releaseNetworkRequest(req1);
283
284 // callback does not trigger anymore.
285 captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_LOSING));
Chalard Jean1afb2e32021-10-04 16:36:32 +0900286 verify(callback, after(SHORT_TIMEOUT_MS).never()).onLosing(any(), anyInt());
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900287
288 // callback can be registered again
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900289 when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
290 anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req2);
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900291 manager.requestNetwork(req2, callback, handler);
292
293 // callback triggers
294 captor.getValue().send(makeMessage(req2, ConnectivityManager.CALLBACK_LOST));
Chalard Jean1afb2e32021-10-04 16:36:32 +0900295 verify(callback, timeout(TIMEOUT_MS).times(1)).onLost(any());
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900296
297 // unregister callback
298 manager.unregisterNetworkCallback(callback);
299 verify(mService, times(1)).releaseNetworkRequest(req2);
300 }
301
302 // TODO: turn on this test when request callback 1:1 mapping is enforced
303 //@Test
304 private void noDoubleCallbackRegistration() throws Exception {
305 ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
306 NetworkRequest request = makeRequest(1);
307 NetworkCallback callback = new ConnectivityManager.NetworkCallback();
308 ApplicationInfo info = new ApplicationInfo();
309 // TODO: update version when starting to enforce 1:1 mapping
310 info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
311
312 when(mCtx.getApplicationInfo()).thenReturn(info);
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900313 when(mService.requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(),
314 anyInt(), any(), nullable(String.class))).thenReturn(request);
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900315
316 Handler handler = new Handler(Looper.getMainLooper());
317 manager.requestNetwork(request, callback, handler);
318
319 // callback is already registered, reregistration should fail.
320 Class<IllegalArgumentException> wantException = IllegalArgumentException.class;
321 expectThrowable(() -> manager.requestNetwork(request, callback), wantException);
322
323 manager.unregisterNetworkCallback(callback);
324 verify(mService, times(1)).releaseNetworkRequest(request);
325
326 // unregistering the callback should make it registrable again.
327 manager.requestNetwork(request, callback);
328 }
329
Hugo Benichi7abd43f2017-05-09 14:09:02 +0900330 @Test
Chiachang Wang859218c2021-09-16 14:38:52 +0800331 public void testDefaultNetworkActiveListener() throws Exception {
332 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
333 final ConnectivityManager.OnNetworkActiveListener listener =
334 mock(ConnectivityManager.OnNetworkActiveListener.class);
335 assertThrows(IllegalArgumentException.class,
336 () -> manager.removeDefaultNetworkActiveListener(listener));
337 manager.addDefaultNetworkActiveListener(listener);
338 verify(mService, times(1)).registerNetworkActivityListener(any());
339 manager.removeDefaultNetworkActiveListener(listener);
340 verify(mService, times(1)).unregisterNetworkActivityListener(any());
Chiachang Wang2de41682021-09-23 10:46:03 +0800341 assertThrows(IllegalArgumentException.class,
342 () -> manager.removeDefaultNetworkActiveListener(listener));
Chiachang Wang859218c2021-09-16 14:38:52 +0800343 }
344
345 @Test
Hugo Benichi7abd43f2017-05-09 14:09:02 +0900346 public void testArgumentValidation() throws Exception {
347 ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
348
349 NetworkRequest request = mock(NetworkRequest.class);
350 NetworkCallback callback = mock(NetworkCallback.class);
351 Handler handler = mock(Handler.class);
352 NetworkCallback nullCallback = null;
353 PendingIntent nullIntent = null;
354
Junyu Lai92c29c52021-06-22 03:03:51 +0000355 mustFail(() -> manager.requestNetwork(null, callback));
356 mustFail(() -> manager.requestNetwork(request, nullCallback));
357 mustFail(() -> manager.requestNetwork(request, callback, null));
358 mustFail(() -> manager.requestNetwork(request, callback, -1));
359 mustFail(() -> manager.requestNetwork(request, nullIntent));
Hugo Benichi7abd43f2017-05-09 14:09:02 +0900360
Junyu Lai92c29c52021-06-22 03:03:51 +0000361 mustFail(() -> manager.requestBackgroundNetwork(null, callback, handler));
362 mustFail(() -> manager.requestBackgroundNetwork(request, null, handler));
363 mustFail(() -> manager.requestBackgroundNetwork(request, callback, null));
Hugo Benichi7abd43f2017-05-09 14:09:02 +0900364
Junyu Lai92c29c52021-06-22 03:03:51 +0000365 mustFail(() -> manager.registerNetworkCallback(null, callback, handler));
366 mustFail(() -> manager.registerNetworkCallback(request, null, handler));
367 mustFail(() -> manager.registerNetworkCallback(request, callback, null));
368 mustFail(() -> manager.registerNetworkCallback(request, nullIntent));
Hugo Benichi7abd43f2017-05-09 14:09:02 +0900369
Junyu Lai92c29c52021-06-22 03:03:51 +0000370 mustFail(() -> manager.registerDefaultNetworkCallback(null, handler));
371 mustFail(() -> manager.registerDefaultNetworkCallback(callback, null));
Lorenzo Colitti76b639e2021-01-29 20:14:04 +0900372
Junyu Lai92c29c52021-06-22 03:03:51 +0000373 mustFail(() -> manager.registerSystemDefaultNetworkCallback(null, handler));
374 mustFail(() -> manager.registerSystemDefaultNetworkCallback(callback, null));
375
376 mustFail(() -> manager.registerBestMatchingNetworkCallback(null, callback, handler));
377 mustFail(() -> manager.registerBestMatchingNetworkCallback(request, null, handler));
378 mustFail(() -> manager.registerBestMatchingNetworkCallback(request, callback, null));
379
380 mustFail(() -> manager.unregisterNetworkCallback(nullCallback));
381 mustFail(() -> manager.unregisterNetworkCallback(nullIntent));
382 mustFail(() -> manager.releaseNetworkRequest(nullIntent));
Hugo Benichi7abd43f2017-05-09 14:09:02 +0900383 }
384
385 static void mustFail(Runnable fn) {
386 try {
387 fn.run();
388 fail();
389 } catch (Exception expected) {
390 }
391 }
392
junyulaiad010792021-01-11 16:53:38 +0800393 @Test
394 public void testRequestType() throws Exception {
395 final String testPkgName = "MyPackage";
Roshan Piusaa24fde2020-12-17 14:53:09 -0800396 final String testAttributionTag = "MyTag";
junyulaiad010792021-01-11 16:53:38 +0800397 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
398 when(mCtx.getOpPackageName()).thenReturn(testPkgName);
Roshan Piusaa24fde2020-12-17 14:53:09 -0800399 when(mCtx.getAttributionTag()).thenReturn(testAttributionTag);
junyulaiad010792021-01-11 16:53:38 +0800400 final NetworkRequest request = makeRequest(1);
401 final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
402
403 manager.requestNetwork(request, callback);
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900404 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
Roshan Pius951c0032020-12-22 15:10:42 -0800405 eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
Roshan Piusaa24fde2020-12-17 14:53:09 -0800406 eq(testPkgName), eq(testAttributionTag));
junyulaiad010792021-01-11 16:53:38 +0800407 reset(mService);
408
409 // Verify that register network callback does not calls requestNetwork at all.
410 manager.registerNetworkCallback(request, callback);
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900411 verify(mService, never()).requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(),
412 anyInt(), anyInt(), any(), any());
Roshan Pius951c0032020-12-22 15:10:42 -0800413 verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(),
Roshan Piusaa24fde2020-12-17 14:53:09 -0800414 eq(testPkgName), eq(testAttributionTag));
junyulaiad010792021-01-11 16:53:38 +0800415 reset(mService);
416
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900417 Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
418
junyulaiad010792021-01-11 16:53:38 +0800419 manager.registerDefaultNetworkCallback(callback);
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900420 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
Roshan Pius951c0032020-12-22 15:10:42 -0800421 eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
Roshan Piusaa24fde2020-12-17 14:53:09 -0800422 eq(testPkgName), eq(testAttributionTag));
junyulaiad010792021-01-11 16:53:38 +0800423 reset(mService);
Junyu Laia62493f2021-01-19 11:10:56 +0000424
Chiachang Wang6ec9b8d2021-04-20 15:41:24 +0800425 manager.registerDefaultNetworkCallbackForUid(42, callback, handler);
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900426 verify(mService).requestNetwork(eq(42), eq(null),
427 eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
428 eq(testPkgName), eq(testAttributionTag));
429
junyulai05738ae2021-04-15 00:39:49 +0800430 manager.requestBackgroundNetwork(request, callback, handler);
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900431 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
Roshan Pius951c0032020-12-22 15:10:42 -0800432 eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
Roshan Piusaa24fde2020-12-17 14:53:09 -0800433 eq(testPkgName), eq(testAttributionTag));
Junyu Laia62493f2021-01-19 11:10:56 +0000434 reset(mService);
Lorenzo Colitti76b639e2021-01-29 20:14:04 +0900435
Lorenzo Colitti76b639e2021-01-29 20:14:04 +0900436 manager.registerSystemDefaultNetworkCallback(callback, handler);
Lorenzo Colitti2a49c5d2021-03-12 22:48:07 +0900437 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
Roshan Pius951c0032020-12-22 15:10:42 -0800438 eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
Lorenzo Colitti76b639e2021-01-29 20:14:04 +0900439 eq(testPkgName), eq(testAttributionTag));
440 reset(mService);
junyulaiad010792021-01-11 16:53:38 +0800441 }
442
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900443 static Message makeMessage(NetworkRequest req, int messageType) {
444 Bundle bundle = new Bundle();
445 bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
Chalard Jeana23bc9e2018-01-30 22:41:41 +0900446 // Pass default objects as we don't care which get passed here
447 bundle.putParcelable(Network.class.getSimpleName(), new Network(1));
448 bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities());
449 bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties());
Hugo Benichi2aa65af2017-03-06 09:17:06 +0900450 Message msg = Message.obtain();
451 msg.what = messageType;
452 msg.setData(bundle);
453 return msg;
454 }
455
456 static NetworkRequest makeRequest(int requestId) {
457 NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
458 return new NetworkRequest(request.networkCapabilities, ConnectivityManager.TYPE_NONE,
459 requestId, NetworkRequest.Type.NONE);
460 }
461
462 static void expectThrowable(Runnable block, Class<? extends Throwable> throwableType) {
463 try {
464 block.run();
465 } catch (Throwable t) {
466 if (t.getClass().equals(throwableType)) {
467 return;
468 }
469 fail("expected exception of type " + throwableType + ", but was " + t.getClass());
470 }
471 fail("expected exception of type " + throwableType);
472 }
markchiened0fab02022-04-26 16:33:47 +0800473
474 private static class MockContext extends BroadcastInterceptingContext {
475 MockContext(Context base) {
476 super(base);
477 }
478
479 @Override
480 public Context getApplicationContext() {
481 return mock(Context.class);
482 }
483 }
484
485 private WeakReference<Context> makeConnectivityManagerAndReturnContext() {
486 // Mockito may have an internal reference to the mock, creating MockContext for testing.
487 final Context c = new MockContext(mock(Context.class));
488
489 new ConnectivityManager(c, mService);
490
491 return new WeakReference<>(c);
492 }
493
494 private void forceGC() {
495 // First GC ensures that objects are collected for finalization, then second GC ensures
496 // they're garbage-collected after being finalized.
497 System.gc();
498 System.runFinalization();
499 System.gc();
500 }
501
502 @Test
503 public void testConnectivityManagerDoesNotLeakContext() throws Exception {
504 final WeakReference<Context> ref = makeConnectivityManagerAndReturnContext();
505
Mark Chien82eb31b2022-12-06 05:34:50 +0000506 final int attempts = 600;
markchiened0fab02022-04-26 16:33:47 +0800507 final long waitIntervalMs = 50;
508 for (int i = 0; i < attempts; i++) {
509 forceGC();
510 if (ref.get() == null) break;
511
512 Thread.sleep(waitIntervalMs);
513 }
514
markchiend2015662022-04-26 18:08:03 +0800515 assertNull("ConnectivityManager weak reference still not null after " + attempts
516 + " attempts", ref.get());
markchiened0fab02022-04-26 16:33:47 +0800517 }
Junyu Laic3dc5b62023-09-06 19:10:02 +0800518
Junyu Laic3dc5b62023-09-06 19:10:02 +0800519 private <T> void mockService(Class<T> clazz, String name, T service) {
520 doReturn(service).when(mCtx).getSystemService(name);
521 doReturn(name).when(mCtx).getSystemServiceName(clazz);
522
523 // If the test suite uses the inline mock maker library, such as for coverage tests,
524 // then the final version of getSystemService must also be mocked, as the real
525 // method will not be called by the test and null object is returned since no mock.
526 // Otherwise, mocking a final method will fail the test.
527 if (mCtx.getSystemService(clazz) == null) {
528 doReturn(service).when(mCtx).getSystemService(clazz);
529 }
530 }
Erik Klinece55eb12017-01-26 18:08:28 +0900531}