NetworkPolicyManagerServiceTest.java revision 46b451fa7da6c0323e80616409cf467d5b1fd01f
1/* 2 * Copyright (C) 2011 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.server; 18 19import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; 20import static android.net.ConnectivityManager.TYPE_WIFI; 21import static android.net.NetworkPolicy.LIMIT_DISABLED; 22import static android.net.NetworkPolicy.WARNING_DISABLED; 23import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND; 24import static android.net.NetworkPolicyManager.POLICY_NONE; 25import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; 26import static android.net.NetworkPolicyManager.computeLastCycleBoundary; 27import static android.net.NetworkPolicyManager.computeNextCycleBoundary; 28import static android.net.NetworkPolicyManager.uidPoliciesToString; 29import static android.net.TrafficStats.KB_IN_BYTES; 30import static android.net.TrafficStats.MB_IN_BYTES; 31import static android.text.format.DateUtils.DAY_IN_MILLIS; 32import static android.text.format.DateUtils.MINUTE_IN_MILLIS; 33import static android.text.format.Time.TIMEZONE_UTC; 34 35import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT; 36import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED; 37import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING; 38 39import static org.junit.Assert.assertEquals; 40import static org.junit.Assert.assertFalse; 41import static org.junit.Assert.assertNotNull; 42import static org.junit.Assert.assertNull; 43import static org.junit.Assert.assertTrue; 44import static org.junit.Assert.fail; 45import static org.mockito.Matchers.any; 46import static org.mockito.Matchers.anyBoolean; 47import static org.mockito.Matchers.anyInt; 48import static org.mockito.Matchers.anyLong; 49import static org.mockito.Matchers.anyString; 50import static org.mockito.Matchers.eq; 51import static org.mockito.Matchers.isA; 52import static org.mockito.Mockito.atLeastOnce; 53import static org.mockito.Mockito.doAnswer; 54import static org.mockito.Mockito.mock; 55import static org.mockito.Mockito.verify; 56import static org.mockito.Mockito.when; 57 58import android.app.ActivityManager; 59import android.app.IActivityManager; 60import android.app.INotificationManager; 61import android.app.IUidObserver; 62import android.app.Notification; 63import android.app.usage.UsageStatsManagerInternal; 64import android.content.Context; 65import android.content.Intent; 66import android.content.pm.ApplicationInfo; 67import android.content.pm.PackageInfo; 68import android.content.pm.PackageManager; 69import android.content.pm.Signature; 70import android.net.IConnectivityManager; 71import android.net.INetworkManagementEventObserver; 72import android.net.INetworkPolicyListener; 73import android.net.INetworkStatsService; 74import android.net.LinkProperties; 75import android.net.NetworkInfo; 76import android.net.NetworkPolicyManager; 77import android.net.NetworkInfo.DetailedState; 78import android.net.NetworkPolicy; 79import android.net.NetworkState; 80import android.net.NetworkStats; 81import android.net.NetworkTemplate; 82import android.os.Binder; 83import android.os.INetworkManagementService; 84import android.os.PowerManagerInternal; 85import android.os.UserHandle; 86import android.support.test.InstrumentationRegistry; 87import android.support.test.runner.AndroidJUnit4; 88import android.text.TextUtils; 89import android.text.format.Time; 90import android.util.Log; 91import android.util.TrustedTime; 92 93import com.android.server.net.NetworkPolicyManagerInternal; 94import com.android.server.net.NetworkPolicyManagerService; 95 96import libcore.io.IoUtils; 97import libcore.io.Streams; 98 99import com.google.common.util.concurrent.AbstractFuture; 100 101import org.junit.After; 102import org.junit.Before; 103import org.junit.BeforeClass; 104import org.junit.Rule; 105import org.junit.Test; 106import org.junit.rules.MethodRule; 107import org.junit.runner.RunWith; 108import org.junit.runners.model.FrameworkMethod; 109import org.junit.runners.model.Statement; 110import org.mockito.ArgumentCaptor; 111import org.mockito.Mock; 112import org.mockito.MockitoAnnotations; 113import org.mockito.invocation.InvocationOnMock; 114import org.mockito.stubbing.Answer; 115 116import java.io.File; 117import java.io.FileOutputStream; 118import java.io.InputStream; 119import java.io.OutputStream; 120import java.lang.annotation.Annotation; 121import java.lang.annotation.ElementType; 122import java.lang.annotation.Retention; 123import java.lang.annotation.RetentionPolicy; 124import java.lang.annotation.Target; 125import java.util.Arrays; 126import java.util.LinkedHashSet; 127import java.util.List; 128import java.util.concurrent.CountDownLatch; 129import java.util.concurrent.ExecutionException; 130import java.util.concurrent.Future; 131import java.util.concurrent.TimeUnit; 132import java.util.concurrent.TimeoutException; 133import java.util.stream.Collectors; 134 135/** 136 * Tests for {@link NetworkPolicyManagerService}. 137 */ 138@RunWith(AndroidJUnit4.class) 139public class NetworkPolicyManagerServiceTest { 140 private static final String TAG = "NetworkPolicyManagerServiceTest"; 141 142 private static final long TEST_START = 1194220800000L; 143 private static final String TEST_IFACE = "test0"; 144 private static final String TEST_SSID = "AndroidAP"; 145 146 private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi(TEST_SSID); 147 148 /** 149 * Path on assets where files used by {@link NetPolicyXml} are located. 150 */ 151 private static final String NETPOLICY_DIR = "NetworkPolicyManagerServiceTest/netpolicy"; 152 153 private BroadcastInterceptingContext mServiceContext; 154 private File mPolicyDir; 155 156 /** 157 * Relative path of the XML file that will be used as {@code netpolicy.xml}. 158 * 159 * <p>Typically set through a {@link NetPolicyXml} annotation in the test method. 160 */ 161 private String mNetpolicyXml; 162 163 164 private @Mock IActivityManager mActivityManager; 165 private @Mock INetworkStatsService mStatsService; 166 private @Mock INetworkManagementService mNetworkManager; 167 private @Mock TrustedTime mTime; 168 private @Mock IConnectivityManager mConnManager; 169 private @Mock INotificationManager mNotifManager; 170 private @Mock PackageManager mPackageManager; 171 172 private IUidObserver mUidObserver; 173 private INetworkManagementEventObserver mNetworkObserver; 174 175 private NetworkPolicyListenerAnswer mPolicyListener; 176 private NetworkPolicyManagerService mService; 177 178 private long mStartTime; 179 private long mElapsedRealtime; 180 181 private static final int USER_ID = 0; 182 183 private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 4; 184 private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 8; 185 private static final int APP_ID_C = android.os.Process.FIRST_APPLICATION_UID + 15; 186 private static final int APP_ID_D = android.os.Process.FIRST_APPLICATION_UID + 16; 187 private static final int APP_ID_E = android.os.Process.FIRST_APPLICATION_UID + 23; 188 private static final int APP_ID_F = android.os.Process.FIRST_APPLICATION_UID + 42; 189 190 private static final int UID_A = UserHandle.getUid(USER_ID, APP_ID_A); 191 private static final int UID_B = UserHandle.getUid(USER_ID, APP_ID_B); 192 private static final int UID_C = UserHandle.getUid(USER_ID, APP_ID_C); 193 private static final int UID_D = UserHandle.getUid(USER_ID, APP_ID_D); 194 private static final int UID_E = UserHandle.getUid(USER_ID, APP_ID_E); 195 private static final int UID_F = UserHandle.getUid(USER_ID, APP_ID_F); 196 197 private static final String PKG_NAME_A = "name.is.A,pkg.A"; 198 199 public final @Rule NetPolicyMethodRule mNetPolicyXmlRule = new NetPolicyMethodRule(); 200 201 @BeforeClass 202 public static void registerLocalServices() { 203 addLocalServiceMock(PowerManagerInternal.class); 204 addLocalServiceMock(DeviceIdleController.LocalService.class); 205 final UsageStatsManagerInternal usageStats = 206 addLocalServiceMock(UsageStatsManagerInternal.class); 207 when(usageStats.getIdleUidsForUser(anyInt())).thenReturn(new int[]{}); 208 } 209 210 @Before 211 public void callSystemReady() throws Exception { 212 MockitoAnnotations.initMocks(this); 213 214 final Context context = InstrumentationRegistry.getContext(); 215 216 setCurrentTimeMillis(TEST_START); 217 218 // intercept various broadcasts, and pretend that uids have packages 219 mServiceContext = new BroadcastInterceptingContext(context) { 220 @Override 221 public PackageManager getPackageManager() { 222 return mPackageManager; 223 } 224 225 @Override 226 public void startActivity(Intent intent) { 227 // ignored 228 } 229 }; 230 231 setNetpolicyXml(context); 232 233 doAnswer(new Answer<Void>() { 234 235 @Override 236 public Void answer(InvocationOnMock invocation) throws Throwable { 237 mUidObserver = (IUidObserver) invocation.getArguments()[0]; 238 Log.d(TAG, "set mUidObserver to " + mUidObserver); 239 return null; 240 } 241 }).when(mActivityManager).registerUidObserver(any(), anyInt()); 242 243 mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService, 244 mNetworkManager, mTime, mPolicyDir, true); 245 mService.bindConnectivityManager(mConnManager); 246 mService.bindNotificationManager(mNotifManager); 247 mPolicyListener = new NetworkPolicyListenerAnswer(mService); 248 249 // Sets some common expectations. 250 when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenAnswer( 251 new Answer<PackageInfo>() { 252 253 @Override 254 public PackageInfo answer(InvocationOnMock invocation) throws Throwable { 255 final String packageName = (String) invocation.getArguments()[0]; 256 final PackageInfo info = new PackageInfo(); 257 final Signature signature; 258 if ("android".equals(packageName)) { 259 signature = new Signature("F00D"); 260 } else { 261 signature = new Signature("DEAD"); 262 } 263 info.signatures = new Signature[] { 264 signature 265 }; 266 return info; 267 } 268 }); 269 when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 270 .thenReturn(new ApplicationInfo()); 271 when(mPackageManager.getPackagesForUid(UID_A)).thenReturn(new String[] {PKG_NAME_A}); 272 when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true); 273 expectCurrentTime(); 274 275 // Prepare NPMS. 276 mService.systemReady(); 277 278 // catch INetworkManagementEventObserver during systemReady() 279 ArgumentCaptor<INetworkManagementEventObserver> networkObserver = 280 ArgumentCaptor.forClass(INetworkManagementEventObserver.class); 281 verify(mNetworkManager).registerObserver(networkObserver.capture()); 282 mNetworkObserver = networkObserver.getValue(); 283 } 284 285 @After 286 public void removeFiles() throws Exception { 287 for (File file : mPolicyDir.listFiles()) { 288 file.delete(); 289 } 290 } 291 292 @After 293 public void unregisterLocalServices() throws Exception { 294 // Registered by NetworkPolicyManagerService's constructor. 295 LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); 296 } 297 298 @Test 299 @NetPolicyXml("restrict-background-lists-whitelist-format.xml") 300 public void testRestrictBackgroundLists_whitelistFormat() throws Exception { 301 restrictBackgroundListsTest(); 302 } 303 304 @Test 305 @NetPolicyXml("restrict-background-lists-uid-policy-format.xml") 306 public void testRestrictBackgroundLists_uidPolicyFormat() throws Exception { 307 restrictBackgroundListsTest(); 308 } 309 310 private void restrictBackgroundListsTest() throws Exception { 311 // UIds that are whitelisted. 312 assertWhitelistUids(UID_A, UID_B, UID_C); 313 assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); 314 assertUidPolicy(UID_B, POLICY_ALLOW_METERED_BACKGROUND); 315 assertUidPolicy(UID_C, POLICY_ALLOW_METERED_BACKGROUND); 316 317 // UIDs that are blacklisted. 318 assertUidPolicy(UID_D, POLICY_NONE); 319 assertUidPolicy(UID_E, POLICY_REJECT_METERED_BACKGROUND); 320 321 // UIDS that have legacy policies. 322 assertUidPolicy(UID_F, 2); // POLICY_ALLOW_BACKGROUND_BATTERY_SAVE 323 324 // Remove whitelist. 325 mService.removeRestrictBackgroundWhitelistedUid(UID_A); 326 assertUidPolicy(UID_A, POLICY_NONE); 327 assertWhitelistUids(UID_B, UID_C); 328 329 // Add whitelist when blacklisted. 330 mService.addRestrictBackgroundWhitelistedUid(UID_E); 331 assertUidPolicy(UID_E, POLICY_ALLOW_METERED_BACKGROUND); 332 assertWhitelistUids(UID_B, UID_C, UID_E); 333 334 // Add blacklist when whitelisted. 335 mService.setUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); 336 assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); 337 assertWhitelistUids(UID_C, UID_E); 338 } 339 340 /** 341 * Tests scenario where an UID had {@code restrict-background} and {@code uid-policy} tags. 342 */ 343 @Test 344 @NetPolicyXml("restrict-background-lists-mixed-format.xml") 345 public void testRestrictBackgroundLists_mixedFormat() throws Exception { 346 assertWhitelistUids(UID_A, UID_C, UID_D); 347 assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); 348 assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); 349 assertUidPolicy(UID_C, (POLICY_ALLOW_METERED_BACKGROUND | 2)); 350 assertUidPolicy(UID_D, POLICY_ALLOW_METERED_BACKGROUND); 351 } 352 353 // NOTE: testPolicyChangeTriggersListener() and testUidForeground() are too superficial, they 354 // don't check for side-effects (like calls to NetworkManagementService) neither cover all 355 // different modes (Data Saver, Battery Saver, Doze, App idle, etc...). 356 // These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests. 357 358 @Test 359 public void testPolicyChangeTriggersListener() throws Exception { 360 mPolicyListener.expect().onRestrictBackgroundBlacklistChanged(anyInt(), anyBoolean()); 361 362 mService.setUidPolicy(APP_ID_A, POLICY_NONE); 363 mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); 364 365 mPolicyListener.waitAndVerify().onRestrictBackgroundBlacklistChanged(APP_ID_A, true); 366 } 367 368 @Test 369 public void testUidForeground() throws Exception { 370 // push all uids into background 371 mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE); 372 mUidObserver.onUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE); 373 assertFalse(mService.isUidForeground(UID_A)); 374 assertFalse(mService.isUidForeground(UID_B)); 375 376 // push one of the uids into foreground 377 mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP); 378 assertTrue(mService.isUidForeground(UID_A)); 379 assertFalse(mService.isUidForeground(UID_B)); 380 381 // and swap another uid into foreground 382 mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE); 383 mUidObserver.onUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP); 384 assertFalse(mService.isUidForeground(UID_A)); 385 assertTrue(mService.isUidForeground(UID_B)); 386 } 387 388 @Test 389 public void testLastCycleBoundaryThisMonth() throws Exception { 390 // assume cycle day of "5th", which should be in same month 391 final long currentTime = parseTime("2007-11-14T00:00:00.000Z"); 392 final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z"); 393 394 final NetworkPolicy policy = new NetworkPolicy( 395 sTemplateWifi, 5, TIMEZONE_UTC, 1024L, 1024L, false); 396 final long actualCycle = computeLastCycleBoundary(currentTime, policy); 397 assertTimeEquals(expectedCycle, actualCycle); 398 } 399 400 @Test 401 public void testLastCycleBoundaryLastMonth() throws Exception { 402 // assume cycle day of "20th", which should be in last month 403 final long currentTime = parseTime("2007-11-14T00:00:00.000Z"); 404 final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z"); 405 406 final NetworkPolicy policy = new NetworkPolicy( 407 sTemplateWifi, 20, TIMEZONE_UTC, 1024L, 1024L, false); 408 final long actualCycle = computeLastCycleBoundary(currentTime, policy); 409 assertTimeEquals(expectedCycle, actualCycle); 410 } 411 412 @Test 413 public void testLastCycleBoundaryThisMonthFebruary() throws Exception { 414 // assume cycle day of "30th" in february; should go to january 415 final long currentTime = parseTime("2007-02-14T00:00:00.000Z"); 416 final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z"); 417 418 final NetworkPolicy policy = new NetworkPolicy( 419 sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false); 420 final long actualCycle = computeLastCycleBoundary(currentTime, policy); 421 assertTimeEquals(expectedCycle, actualCycle); 422 } 423 424 @Test 425 public void testLastCycleBoundaryLastMonthFebruary() throws Exception { 426 // assume cycle day of "30th" in february, which should clamp 427 final long currentTime = parseTime("2007-03-14T00:00:00.000Z"); 428 final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z"); 429 430 final NetworkPolicy policy = new NetworkPolicy( 431 sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false); 432 final long actualCycle = computeLastCycleBoundary(currentTime, policy); 433 assertTimeEquals(expectedCycle, actualCycle); 434 } 435 436 @Test 437 public void testCycleBoundaryLeapYear() throws Exception { 438 final NetworkPolicy policy = new NetworkPolicy( 439 sTemplateWifi, 29, TIMEZONE_UTC, 1024L, 1024L, false); 440 441 assertTimeEquals(parseTime("2012-01-29T00:00:00.000Z"), 442 computeNextCycleBoundary(parseTime("2012-01-14T00:00:00.000Z"), policy)); 443 assertTimeEquals(parseTime("2012-02-29T00:00:00.000Z"), 444 computeNextCycleBoundary(parseTime("2012-02-14T00:00:00.000Z"), policy)); 445 assertTimeEquals(parseTime("2012-02-29T00:00:00.000Z"), 446 computeLastCycleBoundary(parseTime("2012-03-14T00:00:00.000Z"), policy)); 447 assertTimeEquals(parseTime("2012-03-29T00:00:00.000Z"), 448 computeNextCycleBoundary(parseTime("2012-03-14T00:00:00.000Z"), policy)); 449 450 assertTimeEquals(parseTime("2007-01-29T00:00:00.000Z"), 451 computeNextCycleBoundary(parseTime("2007-01-14T00:00:00.000Z"), policy)); 452 assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"), 453 computeNextCycleBoundary(parseTime("2007-02-14T00:00:00.000Z"), policy)); 454 assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"), 455 computeLastCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy)); 456 assertTimeEquals(parseTime("2007-03-29T00:00:00.000Z"), 457 computeNextCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy)); 458 } 459 460 @Test 461 public void testNextCycleTimezoneAfterUtc() throws Exception { 462 // US/Central is UTC-6 463 final NetworkPolicy policy = new NetworkPolicy( 464 sTemplateWifi, 10, "US/Central", 1024L, 1024L, false); 465 assertTimeEquals(parseTime("2012-01-10T06:00:00.000Z"), 466 computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy)); 467 } 468 469 @Test 470 public void testNextCycleTimezoneBeforeUtc() throws Exception { 471 // Israel is UTC+2 472 final NetworkPolicy policy = new NetworkPolicy( 473 sTemplateWifi, 10, "Israel", 1024L, 1024L, false); 474 assertTimeEquals(parseTime("2012-01-09T22:00:00.000Z"), 475 computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy)); 476 } 477 478 @Test 479 public void testNextCycleSane() throws Exception { 480 final NetworkPolicy policy = new NetworkPolicy( 481 sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false); 482 final LinkedHashSet<Long> seen = new LinkedHashSet<Long>(); 483 484 // walk forwards, ensuring that cycle boundaries don't get stuck 485 long currentCycle = computeNextCycleBoundary(parseTime("2011-08-01T00:00:00.000Z"), policy); 486 for (int i = 0; i < 128; i++) { 487 long nextCycle = computeNextCycleBoundary(currentCycle, policy); 488 assertEqualsFuzzy(DAY_IN_MILLIS * 30, nextCycle - currentCycle, DAY_IN_MILLIS * 3); 489 assertUnique(seen, nextCycle); 490 currentCycle = nextCycle; 491 } 492 } 493 494 @Test 495 public void testLastCycleSane() throws Exception { 496 final NetworkPolicy policy = new NetworkPolicy( 497 sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false); 498 final LinkedHashSet<Long> seen = new LinkedHashSet<Long>(); 499 500 // walk backwards, ensuring that cycle boundaries look sane 501 long currentCycle = computeLastCycleBoundary(parseTime("2011-08-04T00:00:00.000Z"), policy); 502 for (int i = 0; i < 128; i++) { 503 long lastCycle = computeLastCycleBoundary(currentCycle, policy); 504 assertEqualsFuzzy(DAY_IN_MILLIS * 30, currentCycle - lastCycle, DAY_IN_MILLIS * 3); 505 assertUnique(seen, lastCycle); 506 currentCycle = lastCycle; 507 } 508 } 509 510 @Test 511 public void testCycleTodayJanuary() throws Exception { 512 final NetworkPolicy policy = new NetworkPolicy( 513 sTemplateWifi, 14, "US/Pacific", 1024L, 1024L, false); 514 515 assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"), 516 computeNextCycleBoundary(parseTime("2013-01-13T23:59:59.000-08:00"), policy)); 517 assertTimeEquals(parseTime("2013-02-14T00:00:00.000-08:00"), 518 computeNextCycleBoundary(parseTime("2013-01-14T00:00:01.000-08:00"), policy)); 519 assertTimeEquals(parseTime("2013-02-14T00:00:00.000-08:00"), 520 computeNextCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy)); 521 522 assertTimeEquals(parseTime("2012-12-14T00:00:00.000-08:00"), 523 computeLastCycleBoundary(parseTime("2013-01-13T23:59:59.000-08:00"), policy)); 524 assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"), 525 computeLastCycleBoundary(parseTime("2013-01-14T00:00:01.000-08:00"), policy)); 526 assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"), 527 computeLastCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy)); 528 } 529 530 @Test 531 public void testLastCycleBoundaryDST() throws Exception { 532 final long currentTime = parseTime("1989-01-02T07:30:00.000"); 533 final long expectedCycle = parseTime("1988-12-03T02:00:00.000Z"); 534 535 final NetworkPolicy policy = new NetworkPolicy( 536 sTemplateWifi, 3, "America/Argentina/Buenos_Aires", 1024L, 1024L, false); 537 final long actualCycle = computeLastCycleBoundary(currentTime, policy); 538 assertTimeEquals(expectedCycle, actualCycle); 539 } 540 541 @Test 542 public void testNetworkPolicyAppliedCycleLastMonth() throws Exception { 543 NetworkState[] state = null; 544 NetworkStats stats = null; 545 546 final long TIME_FEB_15 = 1171497600000L; 547 final long TIME_MAR_10 = 1173484800000L; 548 final int CYCLE_DAY = 15; 549 550 setCurrentTimeMillis(TIME_MAR_10); 551 552 // first, pretend that wifi network comes online. no policy active, 553 // which means we shouldn't push limit to interface. 554 state = new NetworkState[] { buildWifi() }; 555 when(mConnManager.getAllNetworkState()).thenReturn(state); 556 expectCurrentTime(); 557 558 mPolicyListener.expect().onMeteredIfacesChanged(any()); 559 mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); 560 mPolicyListener.waitAndVerify().onMeteredIfacesChanged(any()); 561 562 // now change cycle to be on 15th, and test in early march, to verify we 563 // pick cycle day in previous month. 564 when(mConnManager.getAllNetworkState()).thenReturn(state); 565 expectCurrentTime(); 566 567 // pretend that 512 bytes total have happened 568 stats = new NetworkStats(getElapsedRealtime(), 1) 569 .addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L); 570 when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10)) 571 .thenReturn(stats.getTotalBytes()); 572 573 mPolicyListener.expect().onMeteredIfacesChanged(any()); 574 setNetworkPolicies(new NetworkPolicy( 575 sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false)); 576 mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); 577 578 // TODO: consider making strongly ordered mock 579 verifyPolicyDataEnable(TYPE_WIFI, true); 580 verifyRemoveInterfaceQuota(TEST_IFACE); 581 verifySetInterfaceQuota(TEST_IFACE, (2 * MB_IN_BYTES) - 512); 582 } 583 584 @Test 585 public void testOverWarningLimitNotification() throws Exception { 586 NetworkState[] state = null; 587 NetworkStats stats = null; 588 Future<String> tagFuture = null; 589 590 final long TIME_FEB_15 = 1171497600000L; 591 final long TIME_MAR_10 = 1173484800000L; 592 final int CYCLE_DAY = 15; 593 594 setCurrentTimeMillis(TIME_MAR_10); 595 596 // assign wifi policy 597 state = new NetworkState[] {}; 598 stats = new NetworkStats(getElapsedRealtime(), 1) 599 .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L); 600 601 { 602 expectCurrentTime(); 603 when(mConnManager.getAllNetworkState()).thenReturn(state); 604 when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, 605 currentTimeMillis())).thenReturn(stats.getTotalBytes()); 606 607 mPolicyListener.expect().onMeteredIfacesChanged(any()); 608 setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1 609 * MB_IN_BYTES, 2 * MB_IN_BYTES, false)); 610 mPolicyListener.waitAndVerify().onMeteredIfacesChanged(any()); 611 verifyPolicyDataEnable(TYPE_WIFI, true); 612 } 613 614 // bring up wifi network 615 incrementCurrentTime(MINUTE_IN_MILLIS); 616 state = new NetworkState[] { buildWifi() }; 617 stats = new NetworkStats(getElapsedRealtime(), 1) 618 .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L); 619 620 { 621 expectCurrentTime(); 622 when(mConnManager.getAllNetworkState()).thenReturn(state); 623 when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, 624 currentTimeMillis())).thenReturn(stats.getTotalBytes()); 625 626 mPolicyListener.expect().onMeteredIfacesChanged(any()); 627 mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); 628 mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); 629 630 verifyPolicyDataEnable(TYPE_WIFI, true); 631 verifyRemoveInterfaceQuota(TEST_IFACE); 632 verifySetInterfaceQuota(TEST_IFACE, 2 * MB_IN_BYTES); 633 } 634 635 // go over warning, which should kick notification 636 incrementCurrentTime(MINUTE_IN_MILLIS); 637 stats = new NetworkStats(getElapsedRealtime(), 1) 638 .addIfaceValues(TEST_IFACE, 1536 * KB_IN_BYTES, 15L, 0L, 0L); 639 640 { 641 expectCurrentTime(); 642 when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, 643 currentTimeMillis())).thenReturn(stats.getTotalBytes()); 644 tagFuture = expectEnqueueNotification(); 645 646 mNetworkObserver.limitReached(null, TEST_IFACE); 647 648 assertNotificationType(TYPE_WARNING, tagFuture.get()); 649 verifyPolicyDataEnable(TYPE_WIFI, true); 650 651 } 652 653 // go over limit, which should kick notification and dialog 654 incrementCurrentTime(MINUTE_IN_MILLIS); 655 stats = new NetworkStats(getElapsedRealtime(), 1) 656 .addIfaceValues(TEST_IFACE, 5 * MB_IN_BYTES, 512L, 0L, 0L); 657 658 { 659 expectCurrentTime(); 660 when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, 661 currentTimeMillis())).thenReturn(stats.getTotalBytes()); 662 tagFuture = expectEnqueueNotification(); 663 664 mNetworkObserver.limitReached(null, TEST_IFACE); 665 666 assertNotificationType(TYPE_LIMIT, tagFuture.get()); 667 verifyPolicyDataEnable(TYPE_WIFI, false); 668 } 669 670 // now snooze policy, which should remove quota 671 incrementCurrentTime(MINUTE_IN_MILLIS); 672 673 { 674 expectCurrentTime(); 675 when(mConnManager.getAllNetworkState()).thenReturn(state); 676 when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, 677 currentTimeMillis())).thenReturn(stats.getTotalBytes()); 678 tagFuture = expectEnqueueNotification(); 679 680 mPolicyListener.expect().onMeteredIfacesChanged(any()); 681 mService.snoozeLimit(sTemplateWifi); 682 mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); 683 684 assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get()); 685 // snoozed interface still has high quota so background data is 686 // still restricted. 687 verifyRemoveInterfaceQuota(TEST_IFACE); 688 verifySetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); 689 verifyPolicyDataEnable(TYPE_WIFI, true); 690 } 691 } 692 693 @Test 694 public void testMeteredNetworkWithoutLimit() throws Exception { 695 NetworkState[] state = null; 696 NetworkStats stats = null; 697 698 final long TIME_FEB_15 = 1171497600000L; 699 final long TIME_MAR_10 = 1173484800000L; 700 final int CYCLE_DAY = 15; 701 702 setCurrentTimeMillis(TIME_MAR_10); 703 704 // bring up wifi network with metered policy 705 state = new NetworkState[] { buildWifi() }; 706 stats = new NetworkStats(getElapsedRealtime(), 1) 707 .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L); 708 709 { 710 expectCurrentTime(); 711 when(mConnManager.getAllNetworkState()).thenReturn(state); 712 when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, 713 currentTimeMillis())).thenReturn(stats.getTotalBytes()); 714 715 mPolicyListener.expect().onMeteredIfacesChanged(any()); 716 setNetworkPolicies(new NetworkPolicy( 717 sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, 718 true)); 719 mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); 720 721 verifyPolicyDataEnable(TYPE_WIFI, true); 722 verifyRemoveInterfaceQuota(TEST_IFACE); 723 verifySetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); 724 } 725 } 726 727 private static long parseTime(String time) { 728 final Time result = new Time(); 729 result.parse3339(time); 730 return result.toMillis(true); 731 } 732 733 private void setNetworkPolicies(NetworkPolicy... policies) { 734 mService.setNetworkPolicies(policies); 735 } 736 737 private static NetworkState buildWifi() { 738 final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null); 739 info.setDetailedState(DetailedState.CONNECTED, null, null); 740 final LinkProperties prop = new LinkProperties(); 741 prop.setInterfaceName(TEST_IFACE); 742 return new NetworkState(info, prop, null, null, null, TEST_SSID); 743 } 744 745 private void expectCurrentTime() throws Exception { 746 when(mTime.forceRefresh()).thenReturn(false); 747 when(mTime.hasCache()).thenReturn(true); 748 when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis()); 749 when(mTime.getCacheAge()).thenReturn(0L); 750 when(mTime.getCacheCertainty()).thenReturn(0L); 751 } 752 753 private Future<String> expectEnqueueNotification() throws Exception { 754 final FutureAnswer<String> futureAnswer = new FutureAnswer<String>(2); 755 doAnswer(futureAnswer).when(mNotifManager).enqueueNotificationWithTag( 756 anyString(), anyString(), anyString() /* capture here (index 2)*/, 757 anyInt(), isA(Notification.class), isA(int[].class), anyInt()); 758 return futureAnswer; 759 } 760 761 private void verifySetInterfaceQuota(String iface, long quotaBytes) throws Exception { 762 verify(mNetworkManager, atLeastOnce()).setInterfaceQuota(iface, quotaBytes); 763 } 764 765 private void verifyRemoveInterfaceQuota(String iface) throws Exception { 766 verify(mNetworkManager, atLeastOnce()).removeInterfaceQuota(iface); 767 } 768 769 private Future<Void> verifyPolicyDataEnable(int type, boolean enabled) throws Exception { 770 // TODO: bring back this test 771 return null; 772 } 773 774 private void verifyAdvisePersistThreshold() throws Exception { 775 verify(mStatsService).advisePersistThreshold(anyLong()); 776 } 777 778 private static class TestAbstractFuture<T> extends AbstractFuture<T> { 779 @Override 780 public T get() throws InterruptedException, ExecutionException { 781 try { 782 return get(5, TimeUnit.SECONDS); 783 } catch (TimeoutException e) { 784 throw new RuntimeException(e); 785 } 786 } 787 } 788 789 private static class FutureAnswer<T> extends TestAbstractFuture<T> implements Answer<Void> { 790 private final int index; 791 792 FutureAnswer(int index) { 793 this.index = index; 794 } 795 @Override 796 public Void answer(InvocationOnMock invocation) throws Throwable { 797 @SuppressWarnings("unchecked") 798 T captured = (T) invocation.getArguments()[index]; 799 set(captured); 800 return null; 801 } 802 } 803 804 private static void assertTimeEquals(long expected, long actual) { 805 if (expected != actual) { 806 fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual)); 807 } 808 } 809 810 private static String formatTime(long millis) { 811 final Time time = new Time(Time.TIMEZONE_UTC); 812 time.set(millis); 813 return time.format3339(false); 814 } 815 816 private static void assertEqualsFuzzy(long expected, long actual, long fuzzy) { 817 final long low = expected - fuzzy; 818 final long high = expected + fuzzy; 819 if (actual < low || actual > high) { 820 fail("value " + actual + " is outside [" + low + "," + high + "]"); 821 } 822 } 823 824 private static void assertUnique(LinkedHashSet<Long> seen, Long value) { 825 if (!seen.add(value)) { 826 fail("found duplicate time " + value + " in series " + seen.toString()); 827 } 828 } 829 830 private static void assertNotificationType(int expected, String actualTag) { 831 assertEquals("notification type mismatch for '" + actualTag +"'", 832 Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1)); 833 } 834 835 private void assertUidPolicy(int uid, int expected) { 836 final int actual = mService.getUidPolicy(uid); 837 if (expected != actual) { 838 fail("Wrong policy for UID " + uid + ": expected " + uidPoliciesToString(expected) 839 + ", actual " + uidPoliciesToString(actual)); 840 } 841 } 842 843 private void assertWhitelistUids(int... uids) { 844 assertContainsInAnyOrder(mService.getRestrictBackgroundWhitelistedUids(), uids); 845 } 846 847 // TODO: replace by Truth, Hamcrest, or a similar tool. 848 private void assertContainsInAnyOrder(int[] actual, int...expected) { 849 final StringBuilder errors = new StringBuilder(); 850 if (actual.length != expected.length) { 851 errors.append("\tsize does not match\n"); 852 } 853 final List<Integer> actualList = 854 Arrays.stream(actual).boxed().collect(Collectors.<Integer>toList()); 855 final List<Integer> expectedList = 856 Arrays.stream(expected).boxed().collect(Collectors.<Integer>toList()); 857 if (!actualList.containsAll(expectedList)) { 858 errors.append("\tmissing elements on actual list\n"); 859 } 860 if (!expectedList.containsAll(actualList)) { 861 errors.append("\tmissing elements on expected list\n"); 862 } 863 if (errors.length() > 0) { 864 fail("assertContainsInAnyOrder(expected=" + Arrays.toString(expected) 865 + ", actual=" + Arrays.toString(actual) +") failed: \n" + errors); 866 } 867 } 868 869 private long getElapsedRealtime() { 870 return mElapsedRealtime; 871 } 872 873 private void setCurrentTimeMillis(long currentTimeMillis) { 874 mStartTime = currentTimeMillis; 875 mElapsedRealtime = 0L; 876 } 877 878 private long currentTimeMillis() { 879 return mStartTime + mElapsedRealtime; 880 } 881 882 private void incrementCurrentTime(long duration) { 883 mElapsedRealtime += duration; 884 } 885 886 /** 887 * Creates a mock and registers it to {@link LocalServices}. 888 */ 889 private static <T> T addLocalServiceMock(Class<T> clazz) { 890 final T mock = mock(clazz); 891 LocalServices.addService(clazz, mock); 892 return mock; 893 } 894 895 /** 896 * Custom Mockito answer used to verify async {@link INetworkPolicyListener} calls. 897 * 898 * <p>Typical usage: 899 * <pre><code> 900 * mPolicyListener.expect().someCallback(any()); 901 * // do something on objects under test 902 * mPolicyListener.waitAndVerify().someCallback(eq(expectedValue)); 903 * </code></pre> 904 */ 905 final class NetworkPolicyListenerAnswer implements Answer<Void> { 906 private CountDownLatch latch; 907 private final INetworkPolicyListener listener; 908 909 NetworkPolicyListenerAnswer(NetworkPolicyManagerService service) { 910 this.listener = mock(INetworkPolicyListener.class); 911 // RemoteCallbackList needs a binder to use as key 912 when(listener.asBinder()).thenReturn(new Binder()); 913 service.registerListener(listener); 914 } 915 916 @Override 917 public Void answer(InvocationOnMock invocation) throws Throwable { 918 Log.d(TAG,"counting down on answer: " + invocation); 919 latch.countDown(); 920 return null; 921 } 922 923 INetworkPolicyListener expect() { 924 assertNull("expect() called before waitAndVerify()", latch); 925 latch = new CountDownLatch(1); 926 return doAnswer(this).when(listener); 927 } 928 929 INetworkPolicyListener waitAndVerify() { 930 assertNotNull("waitAndVerify() called before expect()", latch); 931 try { 932 assertTrue("callback not called in 5 seconds", latch.await(5, TimeUnit.SECONDS)); 933 } catch (InterruptedException e) { 934 fail("Thread interrupted before callback called"); 935 } finally { 936 latch = null; 937 } 938 return verify(listener, atLeastOnce()); 939 } 940 } 941 942 private void setNetpolicyXml(Context context) throws Exception { 943 mPolicyDir = context.getFilesDir(); 944 if (mPolicyDir.exists()) { 945 IoUtils.deleteContents(mPolicyDir); 946 } 947 if (!TextUtils.isEmpty(mNetpolicyXml)) { 948 final String assetPath = NETPOLICY_DIR + "/" + mNetpolicyXml; 949 final File netConfigFile = new File(mPolicyDir, "netpolicy.xml"); 950 Log.d(TAG, "Creating " + netConfigFile + " from asset " + assetPath); 951 try (final InputStream in = context.getResources().getAssets().open(assetPath); 952 final OutputStream out = new FileOutputStream(netConfigFile)) { 953 Streams.copy(in, out); 954 } 955 } 956 } 957 958 /** 959 * Annotation used to define the relative path of the {@code netpolicy.xml} file. 960 */ 961 @Retention(RetentionPolicy.RUNTIME) 962 @Target(ElementType.METHOD) 963 public @interface NetPolicyXml { 964 965 public String value() default ""; 966 967 } 968 969 /** 970 * Rule used to set {@code mNetPolicyXml} according to the {@link NetPolicyXml} annotation. 971 */ 972 public static class NetPolicyMethodRule implements MethodRule { 973 974 @Override 975 public Statement apply(Statement base, FrameworkMethod method, Object target) { 976 for (Annotation annotation : method.getAnnotations()) { 977 if ((annotation instanceof NetPolicyXml)) { 978 final String path = ((NetPolicyXml) annotation).value(); 979 if (!path.isEmpty()) { 980 ((NetworkPolicyManagerServiceTest) target).mNetpolicyXml = path; 981 break; 982 } 983 } 984 } 985 return base; 986 } 987 } 988} 989