NetworkPolicyManagerServiceTest.java revision 4ef40087be75b2125ee72f1347099c556d533d42
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_NONE;
24import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
25import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
26import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
27import static android.net.TrafficStats.KB_IN_BYTES;
28import static android.net.TrafficStats.MB_IN_BYTES;
29import static android.text.format.DateUtils.DAY_IN_MILLIS;
30import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
31import static android.text.format.Time.TIMEZONE_UTC;
32
33import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
34import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
35import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
36
37import static org.mockito.Matchers.any;
38import static org.mockito.Matchers.anyBoolean;
39import static org.mockito.Matchers.anyInt;
40import static org.mockito.Matchers.anyLong;
41import static org.mockito.Matchers.anyString;
42import static org.mockito.Matchers.eq;
43import static org.mockito.Matchers.isA;
44import static org.mockito.Mockito.atLeastOnce;
45import static org.mockito.Mockito.doAnswer;
46import static org.mockito.Mockito.mock;
47import static org.mockito.Mockito.verify;
48import static org.mockito.Mockito.when;
49
50import android.app.ActivityManager;
51import android.app.IActivityManager;
52import android.app.INotificationManager;
53import android.app.IUidObserver;
54import android.app.Notification;
55import android.app.usage.UsageStatsManagerInternal;
56import android.content.Context;
57import android.content.Intent;
58import android.content.pm.ApplicationInfo;
59import android.content.pm.PackageInfo;
60import android.content.pm.PackageManager;
61import android.content.pm.Signature;
62import android.net.IConnectivityManager;
63import android.net.INetworkManagementEventObserver;
64import android.net.INetworkPolicyListener;
65import android.net.INetworkStatsService;
66import android.net.LinkProperties;
67import android.net.NetworkInfo;
68import android.net.NetworkInfo.DetailedState;
69import android.net.NetworkPolicy;
70import android.net.NetworkState;
71import android.net.NetworkStats;
72import android.net.NetworkTemplate;
73import android.os.Binder;
74import android.os.INetworkManagementService;
75import android.os.PowerManagerInternal;
76import android.os.UserHandle;
77import android.test.AndroidTestCase;
78import android.text.format.Time;
79import android.util.Log;
80import android.util.TrustedTime;
81
82import com.android.internal.util.test.BroadcastInterceptingContext;
83import com.android.server.net.NetworkPolicyManagerInternal;
84import com.android.server.net.NetworkPolicyManagerService;
85
86import libcore.io.IoUtils;
87
88import com.google.common.util.concurrent.AbstractFuture;
89
90import org.mockito.ArgumentCaptor;
91import org.mockito.Mock;
92import org.mockito.MockitoAnnotations;
93import org.mockito.invocation.InvocationOnMock;
94import org.mockito.stubbing.Answer;
95
96import java.io.File;
97import java.util.ArrayList;
98import java.util.LinkedHashSet;
99import java.util.List;
100import java.util.concurrent.CountDownLatch;
101import java.util.concurrent.ExecutionException;
102import java.util.concurrent.Future;
103import java.util.concurrent.TimeUnit;
104import java.util.concurrent.TimeoutException;
105
106/**
107 * Tests for {@link NetworkPolicyManagerService}.
108 */
109public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
110    private static final String TAG = "NetworkPolicyManagerServiceTest";
111
112    private static final long TEST_START = 1194220800000L;
113    private static final String TEST_IFACE = "test0";
114    private static final String TEST_SSID = "AndroidAP";
115
116    private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi(TEST_SSID);
117
118    private BroadcastInterceptingContext mServiceContext;
119    private File mPolicyDir;
120    private List<Class<?>> mLocalServices = new ArrayList<>();
121
122    private @Mock IActivityManager mActivityManager;
123    private @Mock INetworkStatsService mStatsService;
124    private @Mock INetworkManagementService mNetworkManager;
125    private @Mock TrustedTime mTime;
126    private @Mock IConnectivityManager mConnManager;
127    private @Mock INotificationManager mNotifManager;
128    private @Mock UsageStatsManagerInternal mUsageStats;
129    private @Mock PackageManager mPackageManager;
130
131    private IUidObserver mUidObserver;
132    private INetworkManagementEventObserver mNetworkObserver;
133
134    private NetworkPolicyListenerAnswer mPolicyListener;
135    private NetworkPolicyManagerService mService;
136
137    private long mStartTime;
138    private long mElapsedRealtime;
139
140    private static final int USER_ID = 0;
141
142    private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 800;
143    private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 801;
144
145    private static final int UID_A = UserHandle.getUid(USER_ID, APP_ID_A);
146    private static final int UID_B = UserHandle.getUid(USER_ID, APP_ID_B);
147
148    private static final String PKG_NAME_A = "name.is.A,pkg.A";
149
150    public void setUp() throws Exception {
151        super.setUp();
152
153        MockitoAnnotations.initMocks(this);
154
155        final Context context = getContext();
156
157        setCurrentTimeMillis(TEST_START);
158
159        // intercept various broadcasts, and pretend that uids have packages
160        mServiceContext = new BroadcastInterceptingContext(context) {
161            @Override
162            public PackageManager getPackageManager() {
163                return mPackageManager;
164            }
165
166            @Override
167            public void startActivity(Intent intent) {
168                // ignored
169            }
170        };
171
172        mPolicyDir = context.getFilesDir();
173        if (mPolicyDir.exists()) {
174            IoUtils.deleteContents(mPolicyDir);
175        }
176
177        doAnswer(new Answer<Void>() {
178
179            @Override
180            public Void answer(InvocationOnMock invocation) throws Throwable {
181                mUidObserver = (IUidObserver) invocation.getArguments()[0];
182                Log.d(TAG, "set mUidObserver to " + mUidObserver);
183                return null;
184            }
185        }).when(mActivityManager).registerUidObserver(any(), anyInt());
186
187        addLocalServiceMock(PowerManagerInternal.class);
188        addLocalServiceMock(DeviceIdleController.LocalService.class);
189        addLocalServiceMock(UsageStatsManagerInternal.class, mUsageStats);
190
191        mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
192                mNetworkManager, mTime, mPolicyDir, true);
193        mService.bindConnectivityManager(mConnManager);
194        mService.bindNotificationManager(mNotifManager);
195        mPolicyListener = new NetworkPolicyListenerAnswer(mService);
196
197        // Sets some common expectations.
198        when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenAnswer(
199                new Answer<PackageInfo>() {
200
201                    @Override
202                    public PackageInfo answer(InvocationOnMock invocation) throws Throwable {
203                        final String packageName = (String) invocation.getArguments()[0];
204                        final PackageInfo info = new PackageInfo();
205                        final Signature signature;
206                        if ("android".equals(packageName)) {
207                            signature = new Signature("F00D");
208                        } else {
209                            signature = new Signature("DEAD");
210                        }
211                        info.signatures = new Signature[] {
212                            signature
213                        };
214                        return info;
215                    }
216                });
217        when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
218                .thenReturn(new ApplicationInfo());
219        when(mPackageManager.getPackagesForUid(UID_A)).thenReturn(new String[] {PKG_NAME_A});
220        when(mUsageStats.getIdleUidsForUser(anyInt())).thenReturn(new int[]{});
221        when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true);
222        expectCurrentTime();
223
224        // Prepare NPMS.
225        mService.systemReady();
226
227        // catch INetworkManagementEventObserver during systemReady()
228        ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
229              ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
230        verify(mNetworkManager).registerObserver(networkObserver.capture());
231        mNetworkObserver = networkObserver.getValue();
232    }
233
234    public void tearDown() throws Exception {
235        for (File file : mPolicyDir.listFiles()) {
236            file.delete();
237        }
238
239        mServiceContext = null;
240        mPolicyDir = null;
241
242        mActivityManager = null;
243        mStatsService = null;
244        mTime = null;
245
246        mService = null;
247
248        // TODO: must remove services, otherwise next test will fail.
249        // JUnit4 would avoid that hack by using a static setup.
250        removeLocalServiceMocks();
251
252        // Added by NetworkPolicyManagerService's constructor.
253        LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
254
255        super.tearDown();
256    }
257
258    // NOTE: testPolicyChangeTriggersListener() and testUidForeground() are too superficial, they
259    // don't check for side-effects (like calls to NetworkManagementService) neither cover all
260    // different modes (Data Saver, Battery Saver, Doze, App idle, etc...).
261    // These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests.
262
263    public void testPolicyChangeTriggersListener() throws Exception {
264        mPolicyListener.expect().onRestrictBackgroundBlacklistChanged(anyInt(), anyBoolean());
265
266        mService.setUidPolicy(APP_ID_A, POLICY_NONE);
267        mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
268
269        mPolicyListener.waitAndVerify().onRestrictBackgroundBlacklistChanged(APP_ID_A, true);
270    }
271
272    public void testUidForeground() throws Exception {
273        // push all uids into background
274        mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE);
275        mUidObserver.onUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE);
276        assertFalse(mService.isUidForeground(UID_A));
277        assertFalse(mService.isUidForeground(UID_B));
278
279        // push one of the uids into foreground
280        mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP);
281        assertTrue(mService.isUidForeground(UID_A));
282        assertFalse(mService.isUidForeground(UID_B));
283
284        // and swap another uid into foreground
285        mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE);
286        mUidObserver.onUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP);
287        assertFalse(mService.isUidForeground(UID_A));
288        assertTrue(mService.isUidForeground(UID_B));
289    }
290
291    public void testLastCycleBoundaryThisMonth() throws Exception {
292        // assume cycle day of "5th", which should be in same month
293        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
294        final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
295
296        final NetworkPolicy policy = new NetworkPolicy(
297                sTemplateWifi, 5, TIMEZONE_UTC, 1024L, 1024L, false);
298        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
299        assertTimeEquals(expectedCycle, actualCycle);
300    }
301
302    public void testLastCycleBoundaryLastMonth() throws Exception {
303        // assume cycle day of "20th", which should be in last month
304        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
305        final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
306
307        final NetworkPolicy policy = new NetworkPolicy(
308                sTemplateWifi, 20, TIMEZONE_UTC, 1024L, 1024L, false);
309        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
310        assertTimeEquals(expectedCycle, actualCycle);
311    }
312
313    public void testLastCycleBoundaryThisMonthFebruary() throws Exception {
314        // assume cycle day of "30th" in february; should go to january
315        final long currentTime = parseTime("2007-02-14T00:00:00.000Z");
316        final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
317
318        final NetworkPolicy policy = new NetworkPolicy(
319                sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false);
320        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
321        assertTimeEquals(expectedCycle, actualCycle);
322    }
323
324    public void testLastCycleBoundaryLastMonthFebruary() throws Exception {
325        // assume cycle day of "30th" in february, which should clamp
326        final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
327        final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
328
329        final NetworkPolicy policy = new NetworkPolicy(
330                sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false);
331        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
332        assertTimeEquals(expectedCycle, actualCycle);
333    }
334
335    public void testCycleBoundaryLeapYear() throws Exception {
336        final NetworkPolicy policy = new NetworkPolicy(
337                sTemplateWifi, 29, TIMEZONE_UTC, 1024L, 1024L, false);
338
339        assertTimeEquals(parseTime("2012-01-29T00:00:00.000Z"),
340                computeNextCycleBoundary(parseTime("2012-01-14T00:00:00.000Z"), policy));
341        assertTimeEquals(parseTime("2012-02-29T00:00:00.000Z"),
342                computeNextCycleBoundary(parseTime("2012-02-14T00:00:00.000Z"), policy));
343        assertTimeEquals(parseTime("2012-02-29T00:00:00.000Z"),
344                computeLastCycleBoundary(parseTime("2012-03-14T00:00:00.000Z"), policy));
345        assertTimeEquals(parseTime("2012-03-29T00:00:00.000Z"),
346                computeNextCycleBoundary(parseTime("2012-03-14T00:00:00.000Z"), policy));
347
348        assertTimeEquals(parseTime("2007-01-29T00:00:00.000Z"),
349                computeNextCycleBoundary(parseTime("2007-01-14T00:00:00.000Z"), policy));
350        assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"),
351                computeNextCycleBoundary(parseTime("2007-02-14T00:00:00.000Z"), policy));
352        assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"),
353                computeLastCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy));
354        assertTimeEquals(parseTime("2007-03-29T00:00:00.000Z"),
355                computeNextCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy));
356    }
357
358    public void testNextCycleTimezoneAfterUtc() throws Exception {
359        // US/Central is UTC-6
360        final NetworkPolicy policy = new NetworkPolicy(
361                sTemplateWifi, 10, "US/Central", 1024L, 1024L, false);
362        assertTimeEquals(parseTime("2012-01-10T06:00:00.000Z"),
363                computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy));
364    }
365
366    public void testNextCycleTimezoneBeforeUtc() throws Exception {
367        // Israel is UTC+2
368        final NetworkPolicy policy = new NetworkPolicy(
369                sTemplateWifi, 10, "Israel", 1024L, 1024L, false);
370        assertTimeEquals(parseTime("2012-01-09T22:00:00.000Z"),
371                computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy));
372    }
373
374    public void testNextCycleSane() throws Exception {
375        final NetworkPolicy policy = new NetworkPolicy(
376                sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false);
377        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
378
379        // walk forwards, ensuring that cycle boundaries don't get stuck
380        long currentCycle = computeNextCycleBoundary(parseTime("2011-08-01T00:00:00.000Z"), policy);
381        for (int i = 0; i < 128; i++) {
382            long nextCycle = computeNextCycleBoundary(currentCycle, policy);
383            assertEqualsFuzzy(DAY_IN_MILLIS * 30, nextCycle - currentCycle, DAY_IN_MILLIS * 3);
384            assertUnique(seen, nextCycle);
385            currentCycle = nextCycle;
386        }
387    }
388
389    public void testLastCycleSane() throws Exception {
390        final NetworkPolicy policy = new NetworkPolicy(
391                sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false);
392        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
393
394        // walk backwards, ensuring that cycle boundaries look sane
395        long currentCycle = computeLastCycleBoundary(parseTime("2011-08-04T00:00:00.000Z"), policy);
396        for (int i = 0; i < 128; i++) {
397            long lastCycle = computeLastCycleBoundary(currentCycle, policy);
398            assertEqualsFuzzy(DAY_IN_MILLIS * 30, currentCycle - lastCycle, DAY_IN_MILLIS * 3);
399            assertUnique(seen, lastCycle);
400            currentCycle = lastCycle;
401        }
402    }
403
404    public void testCycleTodayJanuary() throws Exception {
405        final NetworkPolicy policy = new NetworkPolicy(
406                sTemplateWifi, 14, "US/Pacific", 1024L, 1024L, false);
407
408        assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"),
409                computeNextCycleBoundary(parseTime("2013-01-13T23:59:59.000-08:00"), policy));
410        assertTimeEquals(parseTime("2013-02-14T00:00:00.000-08:00"),
411                computeNextCycleBoundary(parseTime("2013-01-14T00:00:01.000-08:00"), policy));
412        assertTimeEquals(parseTime("2013-02-14T00:00:00.000-08:00"),
413                computeNextCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy));
414
415        assertTimeEquals(parseTime("2012-12-14T00:00:00.000-08:00"),
416                computeLastCycleBoundary(parseTime("2013-01-13T23:59:59.000-08:00"), policy));
417        assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"),
418                computeLastCycleBoundary(parseTime("2013-01-14T00:00:01.000-08:00"), policy));
419        assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"),
420                computeLastCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy));
421    }
422
423    public void testLastCycleBoundaryDST() throws Exception {
424        final long currentTime = parseTime("1989-01-02T07:30:00.000");
425        final long expectedCycle = parseTime("1988-12-03T02:00:00.000Z");
426
427        final NetworkPolicy policy = new NetworkPolicy(
428                sTemplateWifi, 3, "America/Argentina/Buenos_Aires", 1024L, 1024L, false);
429        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
430        assertTimeEquals(expectedCycle, actualCycle);
431    }
432
433    public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
434        NetworkState[] state = null;
435        NetworkStats stats = null;
436
437        final long TIME_FEB_15 = 1171497600000L;
438        final long TIME_MAR_10 = 1173484800000L;
439        final int CYCLE_DAY = 15;
440
441        setCurrentTimeMillis(TIME_MAR_10);
442
443        // first, pretend that wifi network comes online. no policy active,
444        // which means we shouldn't push limit to interface.
445        state = new NetworkState[] { buildWifi() };
446        when(mConnManager.getAllNetworkState()).thenReturn(state);
447        expectCurrentTime();
448
449        mPolicyListener.expect().onMeteredIfacesChanged(any());
450        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
451        mPolicyListener.waitAndVerify().onMeteredIfacesChanged(any());
452
453        // now change cycle to be on 15th, and test in early march, to verify we
454        // pick cycle day in previous month.
455        when(mConnManager.getAllNetworkState()).thenReturn(state);
456        expectCurrentTime();
457
458        // pretend that 512 bytes total have happened
459        stats = new NetworkStats(getElapsedRealtime(), 1)
460                .addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L);
461        when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
462                .thenReturn(stats.getTotalBytes());
463
464        mPolicyListener.expect().onMeteredIfacesChanged(any());
465        setNetworkPolicies(new NetworkPolicy(
466                sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
467        mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE}));
468
469        // TODO: consider making strongly ordered mock
470        verifyPolicyDataEnable(TYPE_WIFI, true);
471        verifyRemoveInterfaceQuota(TEST_IFACE);
472        verifySetInterfaceQuota(TEST_IFACE, (2 * MB_IN_BYTES) - 512);
473    }
474
475    public void testOverWarningLimitNotification() throws Exception {
476        NetworkState[] state = null;
477        NetworkStats stats = null;
478        Future<String> tagFuture = null;
479
480        final long TIME_FEB_15 = 1171497600000L;
481        final long TIME_MAR_10 = 1173484800000L;
482        final int CYCLE_DAY = 15;
483
484        setCurrentTimeMillis(TIME_MAR_10);
485
486        // assign wifi policy
487        state = new NetworkState[] {};
488        stats = new NetworkStats(getElapsedRealtime(), 1)
489                .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
490
491        {
492            expectCurrentTime();
493            when(mConnManager.getAllNetworkState()).thenReturn(state);
494            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
495                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
496
497            mPolicyListener.expect().onMeteredIfacesChanged(any());
498            setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1
499                    * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
500            mPolicyListener.waitAndVerify().onMeteredIfacesChanged(any());
501            verifyPolicyDataEnable(TYPE_WIFI, true);
502        }
503
504        // bring up wifi network
505        incrementCurrentTime(MINUTE_IN_MILLIS);
506        state = new NetworkState[] { buildWifi() };
507        stats = new NetworkStats(getElapsedRealtime(), 1)
508                .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
509
510        {
511            expectCurrentTime();
512            when(mConnManager.getAllNetworkState()).thenReturn(state);
513            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
514                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
515
516            mPolicyListener.expect().onMeteredIfacesChanged(any());
517            mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
518            mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE}));
519
520            verifyPolicyDataEnable(TYPE_WIFI, true);
521            verifyRemoveInterfaceQuota(TEST_IFACE);
522            verifySetInterfaceQuota(TEST_IFACE, 2 * MB_IN_BYTES);
523        }
524
525        // go over warning, which should kick notification
526        incrementCurrentTime(MINUTE_IN_MILLIS);
527        stats = new NetworkStats(getElapsedRealtime(), 1)
528                .addIfaceValues(TEST_IFACE, 1536 * KB_IN_BYTES, 15L, 0L, 0L);
529
530        {
531            expectCurrentTime();
532            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
533                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
534            tagFuture = expectEnqueueNotification();
535
536            mNetworkObserver.limitReached(null, TEST_IFACE);
537
538            assertNotificationType(TYPE_WARNING, tagFuture.get());
539            verifyPolicyDataEnable(TYPE_WIFI, true);
540
541        }
542
543        // go over limit, which should kick notification and dialog
544        incrementCurrentTime(MINUTE_IN_MILLIS);
545        stats = new NetworkStats(getElapsedRealtime(), 1)
546                .addIfaceValues(TEST_IFACE, 5 * MB_IN_BYTES, 512L, 0L, 0L);
547
548        {
549            expectCurrentTime();
550            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
551                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
552            tagFuture = expectEnqueueNotification();
553
554            mNetworkObserver.limitReached(null, TEST_IFACE);
555
556            assertNotificationType(TYPE_LIMIT, tagFuture.get());
557            verifyPolicyDataEnable(TYPE_WIFI, false);
558        }
559
560        // now snooze policy, which should remove quota
561        incrementCurrentTime(MINUTE_IN_MILLIS);
562
563        {
564            expectCurrentTime();
565            when(mConnManager.getAllNetworkState()).thenReturn(state);
566            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
567                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
568            tagFuture = expectEnqueueNotification();
569
570            mPolicyListener.expect().onMeteredIfacesChanged(any());
571            mService.snoozeLimit(sTemplateWifi);
572            mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE}));
573
574            assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get());
575            // snoozed interface still has high quota so background data is
576            // still restricted.
577            verifyRemoveInterfaceQuota(TEST_IFACE);
578            verifySetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE);
579            verifyPolicyDataEnable(TYPE_WIFI, true);
580        }
581    }
582
583    public void testMeteredNetworkWithoutLimit() throws Exception {
584        NetworkState[] state = null;
585        NetworkStats stats = null;
586
587        final long TIME_FEB_15 = 1171497600000L;
588        final long TIME_MAR_10 = 1173484800000L;
589        final int CYCLE_DAY = 15;
590
591        setCurrentTimeMillis(TIME_MAR_10);
592
593        // bring up wifi network with metered policy
594        state = new NetworkState[] { buildWifi() };
595        stats = new NetworkStats(getElapsedRealtime(), 1)
596                .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
597
598        {
599            expectCurrentTime();
600            when(mConnManager.getAllNetworkState()).thenReturn(state);
601            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
602                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
603
604            mPolicyListener.expect().onMeteredIfacesChanged(any());
605            setNetworkPolicies(new NetworkPolicy(
606                    sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED,
607                    true));
608            mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE}));
609
610            verifyPolicyDataEnable(TYPE_WIFI, true);
611            verifyRemoveInterfaceQuota(TEST_IFACE);
612            verifySetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE);
613        }
614    }
615
616    private static long parseTime(String time) {
617        final Time result = new Time();
618        result.parse3339(time);
619        return result.toMillis(true);
620    }
621
622    private void setNetworkPolicies(NetworkPolicy... policies) {
623        mService.setNetworkPolicies(policies);
624    }
625
626    private static NetworkState buildWifi() {
627        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
628        info.setDetailedState(DetailedState.CONNECTED, null, null);
629        final LinkProperties prop = new LinkProperties();
630        prop.setInterfaceName(TEST_IFACE);
631        return new NetworkState(info, prop, null, null, null, TEST_SSID);
632    }
633
634    private void expectCurrentTime() throws Exception {
635        when(mTime.forceRefresh()).thenReturn(false);
636        when(mTime.hasCache()).thenReturn(true);
637        when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis());
638        when(mTime.getCacheAge()).thenReturn(0L);
639        when(mTime.getCacheCertainty()).thenReturn(0L);
640    }
641
642    private Future<String> expectEnqueueNotification() throws Exception {
643        final FutureAnswer<String> futureAnswer = new FutureAnswer<String>(2);
644        doAnswer(futureAnswer).when(mNotifManager).enqueueNotificationWithTag(
645                anyString(), anyString(), anyString() /* capture here (index 2)*/,
646                anyInt(), isA(Notification.class), isA(int[].class), anyInt());
647        return futureAnswer;
648    }
649
650    private void verifySetInterfaceQuota(String iface, long quotaBytes) throws Exception {
651        verify(mNetworkManager, atLeastOnce()).setInterfaceQuota(iface, quotaBytes);
652    }
653
654    private void verifyRemoveInterfaceQuota(String iface) throws Exception {
655        verify(mNetworkManager, atLeastOnce()).removeInterfaceQuota(iface);
656    }
657
658    private Future<Void> verifyPolicyDataEnable(int type, boolean enabled) throws Exception {
659        // TODO: bring back this test
660        return null;
661    }
662
663    private void verifyAdvisePersistThreshold() throws Exception {
664        verify(mStatsService).advisePersistThreshold(anyLong());
665    }
666
667    private static class TestAbstractFuture<T> extends AbstractFuture<T> {
668        @Override
669        public T get() throws InterruptedException, ExecutionException {
670            try {
671                return get(5, TimeUnit.SECONDS);
672            } catch (TimeoutException e) {
673                throw new RuntimeException(e);
674            }
675        }
676    }
677
678    private static class FutureAnswer<T> extends TestAbstractFuture<T> implements Answer<Void> {
679        private final int index;
680
681        FutureAnswer(int index) {
682            this.index = index;
683        }
684        @Override
685        public Void answer(InvocationOnMock invocation) throws Throwable {
686            @SuppressWarnings("unchecked")
687            T captured = (T) invocation.getArguments()[index];
688            set(captured);
689            return null;
690        }
691    }
692
693    private static void assertTimeEquals(long expected, long actual) {
694        if (expected != actual) {
695            fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual));
696        }
697    }
698
699    private static String formatTime(long millis) {
700        final Time time = new Time(Time.TIMEZONE_UTC);
701        time.set(millis);
702        return time.format3339(false);
703    }
704
705    private static void assertEqualsFuzzy(long expected, long actual, long fuzzy) {
706        final long low = expected - fuzzy;
707        final long high = expected + fuzzy;
708        if (actual < low || actual > high) {
709            fail("value " + actual + " is outside [" + low + "," + high + "]");
710        }
711    }
712
713    private static void assertUnique(LinkedHashSet<Long> seen, Long value) {
714        if (!seen.add(value)) {
715            fail("found duplicate time " + value + " in series " + seen.toString());
716        }
717    }
718
719    private static void assertNotificationType(int expected, String actualTag) {
720        assertEquals("notification type mismatch for '" + actualTag +"'",
721                Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1));
722    }
723
724    private long getElapsedRealtime() {
725        return mElapsedRealtime;
726    }
727
728    private void setCurrentTimeMillis(long currentTimeMillis) {
729        mStartTime = currentTimeMillis;
730        mElapsedRealtime = 0L;
731    }
732
733    private long currentTimeMillis() {
734        return mStartTime + mElapsedRealtime;
735    }
736
737    private void incrementCurrentTime(long duration) {
738        mElapsedRealtime += duration;
739    }
740
741    /**
742     * Creates a mock and registers it to {@link LocalServices}.
743     */
744    private <T> T addLocalServiceMock(Class<T> clazz) {
745        final T mock = mock(clazz);
746        return addLocalServiceMock(clazz, mock);
747    }
748
749    /**
750     * Registers a mock to {@link LocalServices}.
751     */
752    private <T> T addLocalServiceMock(Class<T> clazz, T mock) {
753        LocalServices.addService(clazz, mock);
754        mLocalServices.add(clazz);
755        return mock;
756    }
757
758    /**
759     * Unregisters all mocks from {@link LocalServices}.
760     */
761    private void removeLocalServiceMocks() {
762        for (Class<?> clazz : mLocalServices) {
763            Log.d(TAG, "removeLocalServiceMock(): " + clazz.getName());
764            LocalServices.removeServiceForTest(clazz);
765        }
766        mLocalServices.clear();
767    }
768
769    /**
770     * Custom Mockito answer used to verify async {@link INetworkPolicyListener} calls.
771     *
772     * <p>Typical usage:
773     * <pre><code>
774     *    mPolicyListener.expect().someCallback(any());
775     *    // do something on objects under test
776     *    mPolicyListener.waitAndVerify().someCallback(eq(expectedValue));
777     * </code></pre>
778     */
779    final class NetworkPolicyListenerAnswer implements Answer<Void> {
780        private CountDownLatch latch;
781        private final INetworkPolicyListener listener;
782
783        NetworkPolicyListenerAnswer(NetworkPolicyManagerService service) {
784            this.listener = mock(INetworkPolicyListener.class);
785            // RemoteCallbackList needs a binder to use as key
786            when(listener.asBinder()).thenReturn(new Binder());
787            service.registerListener(listener);
788        }
789
790        @Override
791        public Void answer(InvocationOnMock invocation) throws Throwable {
792            Log.d(TAG,"counting down on answer: " + invocation);
793            latch.countDown();
794            return null;
795        }
796
797        INetworkPolicyListener expect() {
798            assertNull("expect() called before waitAndVerify()", latch);
799            latch = new CountDownLatch(1);
800            return doAnswer(this).when(listener);
801        }
802
803        INetworkPolicyListener waitAndVerify() {
804            assertNotNull("waitAndVerify() called before expect()", latch);
805            try {
806                assertTrue("callback not called in 5 seconds", latch.await(5, TimeUnit.SECONDS));
807            } catch (InterruptedException e) {
808                fail("Thread interrupted before callback called");
809            } finally {
810                latch = null;
811            }
812            return verify(listener, atLeastOnce());
813        }
814    }
815}
816