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 17 package com.android.server.connectivity; 18 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertTrue; 21 import static org.mockito.Mockito.any; 22 import static org.mockito.Mockito.anyBoolean; 23 import static org.mockito.Mockito.anyInt; 24 import static org.mockito.Mockito.doReturn; 25 import static org.mockito.Mockito.eq; 26 import static org.mockito.Mockito.never; 27 import static org.mockito.Mockito.reset; 28 import static org.mockito.Mockito.times; 29 import static org.mockito.Mockito.verify; 30 import static org.mockito.Mockito.when; 31 32 import android.app.PendingIntent; 33 import android.content.Context; 34 import android.content.pm.PackageManager; 35 import android.content.res.Resources; 36 import android.net.ConnectivityManager; 37 import android.net.IDnsResolver; 38 import android.net.INetd; 39 import android.net.LinkProperties; 40 import android.net.Network; 41 import android.net.NetworkAgentConfig; 42 import android.net.NetworkCapabilities; 43 import android.net.NetworkInfo; 44 import android.net.NetworkProvider; 45 import android.net.NetworkScore; 46 import android.os.Binder; 47 import android.os.Build; 48 import android.text.format.DateUtils; 49 50 import androidx.test.filters.SmallTest; 51 52 import com.android.connectivity.resources.R; 53 import com.android.server.ConnectivityService; 54 import com.android.server.connectivity.NetworkNotificationManager.NotificationType; 55 import com.android.testutils.DevSdkIgnoreRule; 56 import com.android.testutils.DevSdkIgnoreRunner; 57 58 import org.junit.After; 59 import org.junit.Before; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 import org.mockito.Mock; 63 import org.mockito.MockitoAnnotations; 64 65 @RunWith(DevSdkIgnoreRunner.class) 66 @SmallTest 67 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) 68 public class LingerMonitorTest { 69 static final String CELLULAR = "CELLULAR"; 70 static final String WIFI = "WIFI"; 71 72 static final long LOW_RATE_LIMIT = DateUtils.MINUTE_IN_MILLIS; 73 static final long HIGH_RATE_LIMIT = 0; 74 75 static final int LOW_DAILY_LIMIT = 2; 76 static final int HIGH_DAILY_LIMIT = 1000; 77 78 private static final int TEST_LINGER_DELAY_MS = 400; 79 80 LingerMonitor mMonitor; 81 82 @Mock ConnectivityService mConnService; 83 @Mock IDnsResolver mDnsResolver; 84 @Mock INetd mNetd; 85 @Mock Context mCtx; 86 @Mock NetworkNotificationManager mNotifier; 87 @Mock Resources mResources; 88 @Mock QosCallbackTracker mQosCallbackTracker; 89 @Mock PackageManager mPackageManager; 90 91 @Before setUp()92 public void setUp() { 93 MockitoAnnotations.initMocks(this); 94 when(mCtx.getResources()).thenReturn(mResources); 95 when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity"); 96 doReturn(mPackageManager).when(mCtx).getPackageManager(); 97 ConnectivityResources.setResourcesContextForTest(mCtx); 98 99 mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT); 100 } 101 102 @After tearDown()103 public void tearDown() { 104 ConnectivityResources.setResourcesContextForTest(null); 105 } 106 107 @Test testTransitions()108 public void testTransitions() { 109 setNotificationSwitch(transition(WIFI, CELLULAR)); 110 NetworkAgentInfo nai1 = wifiNai(100); 111 NetworkAgentInfo nai2 = cellNai(101); 112 113 assertTrue(mMonitor.isNotificationEnabled(nai1, nai2)); 114 assertFalse(mMonitor.isNotificationEnabled(nai2, nai1)); 115 } 116 117 @Test testNotificationOnLinger()118 public void testNotificationOnLinger() { 119 setNotificationSwitch(transition(WIFI, CELLULAR)); 120 setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); 121 NetworkAgentInfo from = wifiNai(100); 122 NetworkAgentInfo to = cellNai(101); 123 124 mMonitor.noteLingerDefaultNetwork(from, to); 125 verifyNotification(from, to); 126 } 127 128 @Test testToastOnLinger()129 public void testToastOnLinger() { 130 setNotificationSwitch(transition(WIFI, CELLULAR)); 131 setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); 132 NetworkAgentInfo from = wifiNai(100); 133 NetworkAgentInfo to = cellNai(101); 134 135 mMonitor.noteLingerDefaultNetwork(from, to); 136 verifyToast(from, to); 137 } 138 139 @Test testNotificationClearedAfterDisconnect()140 public void testNotificationClearedAfterDisconnect() { 141 setNotificationSwitch(transition(WIFI, CELLULAR)); 142 setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); 143 NetworkAgentInfo from = wifiNai(100); 144 NetworkAgentInfo to = cellNai(101); 145 146 mMonitor.noteLingerDefaultNetwork(from, to); 147 verifyNotification(from, to); 148 149 mMonitor.noteDisconnect(to); 150 verify(mNotifier, times(1)).clearNotification(100); 151 } 152 153 @Test testNotificationClearedAfterSwitchingBack()154 public void testNotificationClearedAfterSwitchingBack() { 155 setNotificationSwitch(transition(WIFI, CELLULAR)); 156 setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); 157 NetworkAgentInfo from = wifiNai(100); 158 NetworkAgentInfo to = cellNai(101); 159 160 mMonitor.noteLingerDefaultNetwork(from, to); 161 verifyNotification(from, to); 162 163 mMonitor.noteLingerDefaultNetwork(to, from); 164 verify(mNotifier, times(1)).clearNotification(100); 165 } 166 167 @Test testUniqueToast()168 public void testUniqueToast() { 169 setNotificationSwitch(transition(WIFI, CELLULAR)); 170 setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); 171 NetworkAgentInfo from = wifiNai(100); 172 NetworkAgentInfo to = cellNai(101); 173 174 mMonitor.noteLingerDefaultNetwork(from, to); 175 verifyToast(from, to); 176 177 mMonitor.noteLingerDefaultNetwork(to, from); 178 verify(mNotifier, times(1)).clearNotification(100); 179 180 reset(mNotifier); 181 mMonitor.noteLingerDefaultNetwork(from, to); 182 verifyNoNotifications(); 183 } 184 185 @Test testMultipleNotifications()186 public void testMultipleNotifications() { 187 setNotificationSwitch(transition(WIFI, CELLULAR)); 188 setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); 189 NetworkAgentInfo wifi1 = wifiNai(100); 190 NetworkAgentInfo wifi2 = wifiNai(101); 191 NetworkAgentInfo cell = cellNai(102); 192 193 mMonitor.noteLingerDefaultNetwork(wifi1, cell); 194 verifyNotification(wifi1, cell); 195 196 mMonitor.noteLingerDefaultNetwork(cell, wifi2); 197 verify(mNotifier, times(1)).clearNotification(100); 198 199 reset(mNotifier); 200 mMonitor.noteLingerDefaultNetwork(wifi2, cell); 201 verifyNotification(wifi2, cell); 202 } 203 204 @Test testRateLimiting()205 public void testRateLimiting() throws InterruptedException { 206 mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT); 207 208 setNotificationSwitch(transition(WIFI, CELLULAR)); 209 setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); 210 NetworkAgentInfo wifi1 = wifiNai(100); 211 NetworkAgentInfo wifi2 = wifiNai(101); 212 NetworkAgentInfo wifi3 = wifiNai(102); 213 NetworkAgentInfo cell = cellNai(103); 214 215 mMonitor.noteLingerDefaultNetwork(wifi1, cell); 216 verifyNotification(wifi1, cell); 217 reset(mNotifier); 218 219 Thread.sleep(50); 220 mMonitor.noteLingerDefaultNetwork(cell, wifi2); 221 mMonitor.noteLingerDefaultNetwork(wifi2, cell); 222 verifyNoNotifications(); 223 224 Thread.sleep(50); 225 mMonitor.noteLingerDefaultNetwork(cell, wifi3); 226 mMonitor.noteLingerDefaultNetwork(wifi3, cell); 227 verifyNoNotifications(); 228 } 229 230 @Test testDailyLimiting()231 public void testDailyLimiting() throws InterruptedException { 232 mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT); 233 234 setNotificationSwitch(transition(WIFI, CELLULAR)); 235 setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); 236 NetworkAgentInfo wifi1 = wifiNai(100); 237 NetworkAgentInfo wifi2 = wifiNai(101); 238 NetworkAgentInfo wifi3 = wifiNai(102); 239 NetworkAgentInfo cell = cellNai(103); 240 241 mMonitor.noteLingerDefaultNetwork(wifi1, cell); 242 verifyNotification(wifi1, cell); 243 reset(mNotifier); 244 245 Thread.sleep(50); 246 mMonitor.noteLingerDefaultNetwork(cell, wifi2); 247 mMonitor.noteLingerDefaultNetwork(wifi2, cell); 248 verifyNotification(wifi2, cell); 249 reset(mNotifier); 250 251 Thread.sleep(50); 252 mMonitor.noteLingerDefaultNetwork(cell, wifi3); 253 mMonitor.noteLingerDefaultNetwork(wifi3, cell); 254 verifyNoNotifications(); 255 } 256 257 @Test testUniqueNotification()258 public void testUniqueNotification() { 259 setNotificationSwitch(transition(WIFI, CELLULAR)); 260 setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION); 261 NetworkAgentInfo from = wifiNai(100); 262 NetworkAgentInfo to = cellNai(101); 263 264 mMonitor.noteLingerDefaultNetwork(from, to); 265 verifyNotification(from, to); 266 267 mMonitor.noteLingerDefaultNetwork(to, from); 268 verify(mNotifier, times(1)).clearNotification(100); 269 270 mMonitor.noteLingerDefaultNetwork(from, to); 271 verifyNotification(from, to); 272 } 273 274 @Test testIgnoreNeverValidatedNetworks()275 public void testIgnoreNeverValidatedNetworks() { 276 setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); 277 setNotificationSwitch(transition(WIFI, CELLULAR)); 278 NetworkAgentInfo from = wifiNai(100, false /* setEverValidated */); 279 NetworkAgentInfo to = cellNai(101); 280 281 mMonitor.noteLingerDefaultNetwork(from, to); 282 verifyNoNotifications(); 283 } 284 285 @Test testIgnoreCurrentlyValidatedNetworks()286 public void testIgnoreCurrentlyValidatedNetworks() { 287 setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); 288 setNotificationSwitch(transition(WIFI, CELLULAR)); 289 NetworkAgentInfo from = wifiNai(100); 290 NetworkAgentInfo to = cellNai(101); 291 from.setValidated(true); 292 293 mMonitor.noteLingerDefaultNetwork(from, to); 294 verifyNoNotifications(); 295 } 296 297 @Test testNoNotificationType()298 public void testNoNotificationType() { 299 setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); 300 setNotificationSwitch(); 301 NetworkAgentInfo from = wifiNai(100); 302 NetworkAgentInfo to = cellNai(101); 303 304 mMonitor.noteLingerDefaultNetwork(from, to); 305 verifyNoNotifications(); 306 } 307 308 @Test testNoTransitionToNotify()309 public void testNoTransitionToNotify() { 310 setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE); 311 setNotificationSwitch(transition(WIFI, CELLULAR)); 312 NetworkAgentInfo from = wifiNai(100); 313 NetworkAgentInfo to = cellNai(101); 314 315 mMonitor.noteLingerDefaultNetwork(from, to); 316 verifyNoNotifications(); 317 } 318 319 @Test testDifferentTransitionToNotify()320 public void testDifferentTransitionToNotify() { 321 setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST); 322 setNotificationSwitch(transition(CELLULAR, WIFI)); 323 NetworkAgentInfo from = wifiNai(100); 324 NetworkAgentInfo to = cellNai(101); 325 326 mMonitor.noteLingerDefaultNetwork(from, to); 327 verifyNoNotifications(); 328 } 329 setNotificationSwitch(String... transitions)330 void setNotificationSwitch(String... transitions) { 331 when(mResources.getStringArray(R.array.config_networkNotifySwitches)) 332 .thenReturn(transitions); 333 } 334 transition(String from, String to)335 String transition(String from, String to) { 336 return from + "-" + to; 337 } 338 setNotificationType(int type)339 void setNotificationType(int type) { 340 when(mResources.getInteger(R.integer.config_networkNotifySwitchType)).thenReturn(type); 341 } 342 verifyNoToast()343 void verifyNoToast() { 344 verify(mNotifier, never()).showToast(any(), any()); 345 } 346 verifyNoNotification()347 void verifyNoNotification() { 348 verify(mNotifier, never()) 349 .showNotification(anyInt(), any(), any(), any(), any(), anyBoolean()); 350 } 351 verifyNoNotifications()352 void verifyNoNotifications() { 353 verifyNoToast(); 354 verifyNoNotification(); 355 } 356 verifyToast(NetworkAgentInfo from, NetworkAgentInfo to)357 void verifyToast(NetworkAgentInfo from, NetworkAgentInfo to) { 358 verifyNoNotification(); 359 verify(mNotifier, times(1)).showToast(from, to); 360 } 361 verifyNotification(NetworkAgentInfo from, NetworkAgentInfo to)362 void verifyNotification(NetworkAgentInfo from, NetworkAgentInfo to) { 363 verifyNoToast(); 364 verify(mNotifier, times(1)).showNotification(eq(from.network.netId), 365 eq(NotificationType.NETWORK_SWITCH), eq(from), eq(to), any(), eq(true)); 366 } 367 nai(int netId, int transport, int networkType, String networkTypeName, boolean setEverValidated)368 NetworkAgentInfo nai(int netId, int transport, int networkType, String networkTypeName, 369 boolean setEverValidated) { 370 NetworkInfo info = new NetworkInfo(networkType, 0, networkTypeName, ""); 371 NetworkCapabilities caps = new NetworkCapabilities(); 372 caps.addCapability(0); 373 caps.addTransportType(transport); 374 NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, 375 new LinkProperties(), caps, null /* localNetworkConfiguration */, 376 new NetworkScore.Builder().setLegacyInt(50).build(), mCtx, null, 377 new NetworkAgentConfig.Builder().build(), mConnService, mNetd, mDnsResolver, 378 NetworkProvider.ID_NONE, Binder.getCallingUid(), TEST_LINGER_DELAY_MS, 379 mQosCallbackTracker, new ConnectivityService.Dependencies()); 380 if (setEverValidated) { 381 // As tests in this class deal with testing lingering, most tests are interested 382 // in networks that can be lingered, and therefore must have validated in the past. 383 // Thus, pretend the network validated once, then became invalidated. 384 nai.setValidated(true); 385 nai.setValidated(false); 386 } 387 return nai; 388 } 389 wifiNai(int netId)390 NetworkAgentInfo wifiNai(int netId) { 391 return wifiNai(netId, true /* setEverValidated */); 392 } 393 wifiNai(int netId, boolean setEverValidated)394 NetworkAgentInfo wifiNai(int netId, boolean setEverValidated) { 395 return nai(netId, NetworkCapabilities.TRANSPORT_WIFI, 396 ConnectivityManager.TYPE_WIFI, WIFI, setEverValidated); 397 } 398 cellNai(int netId)399 NetworkAgentInfo cellNai(int netId) { 400 return cellNai(netId, true /* setEverValidated */); 401 } 402 cellNai(int netId, boolean setEverValidated)403 NetworkAgentInfo cellNai(int netId, boolean setEverValidated) { 404 return nai(netId, NetworkCapabilities.TRANSPORT_CELLULAR, 405 ConnectivityManager.TYPE_MOBILE, CELLULAR, setEverValidated); 406 } 407 408 public static class TestableLingerMonitor extends LingerMonitor { TestableLingerMonitor(Context c, NetworkNotificationManager n, int l, long r)409 public TestableLingerMonitor(Context c, NetworkNotificationManager n, int l, long r) { 410 super(c, n, l, r); 411 } createNotificationIntent()412 @Override protected PendingIntent createNotificationIntent() { 413 return null; 414 } 415 } 416 } 417