NetworkPolicyManagerServiceTest.java revision af82ea2abf53b6825fbbce23434419527d8e8b5c
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.content.Intent.ACTION_UID_REMOVED;
20import static android.content.Intent.EXTRA_UID;
21import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
22import static android.net.ConnectivityManager.TYPE_WIFI;
23import static android.net.NetworkPolicy.LIMIT_DISABLED;
24import static android.net.NetworkPolicy.SNOOZE_NEVER;
25import static android.net.NetworkPolicy.WARNING_DISABLED;
26import static android.net.NetworkPolicyManager.POLICY_NONE;
27import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
28import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
29import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
30import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
31import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
32import static android.net.NetworkStats.TAG_NONE;
33import static android.net.NetworkStats.UID_ALL;
34import static android.text.format.DateUtils.DAY_IN_MILLIS;
35import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
36import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
37import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
38import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
39import static org.easymock.EasyMock.anyInt;
40import static org.easymock.EasyMock.aryEq;
41import static org.easymock.EasyMock.capture;
42import static org.easymock.EasyMock.createMock;
43import static org.easymock.EasyMock.eq;
44import static org.easymock.EasyMock.expect;
45import static org.easymock.EasyMock.expectLastCall;
46import static org.easymock.EasyMock.isA;
47
48import android.app.IActivityManager;
49import android.app.INotificationManager;
50import android.app.IProcessObserver;
51import android.app.Notification;
52import android.content.Intent;
53import android.content.pm.PackageInfo;
54import android.content.pm.PackageManager;
55import android.content.pm.Signature;
56import android.net.ConnectivityManager;
57import android.net.IConnectivityManager;
58import android.net.INetworkManagementEventObserver;
59import android.net.INetworkPolicyListener;
60import android.net.INetworkStatsService;
61import android.net.LinkProperties;
62import android.net.NetworkInfo;
63import android.net.NetworkInfo.DetailedState;
64import android.net.NetworkPolicy;
65import android.net.NetworkState;
66import android.net.NetworkStats;
67import android.net.NetworkTemplate;
68import android.os.Binder;
69import android.os.INetworkManagementService;
70import android.os.IPowerManager;
71import android.test.AndroidTestCase;
72import android.test.mock.MockPackageManager;
73import android.test.suitebuilder.annotation.LargeTest;
74import android.test.suitebuilder.annotation.Suppress;
75import android.text.format.Time;
76import android.util.TrustedTime;
77
78import com.android.server.net.NetworkPolicyManagerService;
79import com.google.common.util.concurrent.AbstractFuture;
80
81import org.easymock.Capture;
82import org.easymock.EasyMock;
83import org.easymock.IAnswer;
84
85import java.io.File;
86import java.util.LinkedHashSet;
87import java.util.concurrent.ExecutionException;
88import java.util.concurrent.Future;
89import java.util.concurrent.TimeUnit;
90import java.util.concurrent.TimeoutException;
91
92/**
93 * Tests for {@link NetworkPolicyManagerService}.
94 */
95@LargeTest
96public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
97    private static final String TAG = "NetworkPolicyManagerServiceTest";
98
99    private static final long TEST_START = 1194220800000L;
100    private static final String TEST_IFACE = "test0";
101
102    private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi();
103
104    private BroadcastInterceptingContext mServiceContext;
105    private File mPolicyDir;
106
107    private IActivityManager mActivityManager;
108    private IPowerManager mPowerManager;
109    private INetworkStatsService mStatsService;
110    private INetworkManagementService mNetworkManager;
111    private INetworkPolicyListener mPolicyListener;
112    private TrustedTime mTime;
113    private IConnectivityManager mConnManager;
114    private INotificationManager mNotifManager;
115
116    private NetworkPolicyManagerService mService;
117    private IProcessObserver mProcessObserver;
118    private INetworkManagementEventObserver mNetworkObserver;
119
120    private Binder mStubBinder = new Binder();
121
122    private static final int UID_A = android.os.Process.FIRST_APPLICATION_UID + 800;
123    private static final int UID_B = android.os.Process.FIRST_APPLICATION_UID + 801;
124
125    private static final int PID_1 = 400;
126    private static final int PID_2 = 401;
127    private static final int PID_3 = 402;
128
129    @Override
130    public void setUp() throws Exception {
131        super.setUp();
132
133        // intercept various broadcasts, and pretend that uids have packages
134        mServiceContext = new BroadcastInterceptingContext(getContext()) {
135            @Override
136            public PackageManager getPackageManager() {
137                return new MockPackageManager() {
138                    @Override
139                    public String[] getPackagesForUid(int uid) {
140                        return new String[] { "com.example" };
141                    }
142
143                    @Override
144                    public PackageInfo getPackageInfo(String packageName, int flags) {
145                        final PackageInfo info = new PackageInfo();
146                        final Signature signature;
147                        if ("android".equals(packageName)) {
148                            signature = new Signature("F00D");
149                        } else {
150                            signature = new Signature("DEAD");
151                        }
152                        info.signatures = new Signature[] { signature };
153                        return info;
154                    }
155                };
156            }
157
158            @Override
159            public void startActivity(Intent intent) {
160                // ignored
161            }
162        };
163
164        mPolicyDir = getContext().getFilesDir();
165        for (File file : mPolicyDir.listFiles()) {
166            file.delete();
167        }
168
169        mActivityManager = createMock(IActivityManager.class);
170        mPowerManager = createMock(IPowerManager.class);
171        mStatsService = createMock(INetworkStatsService.class);
172        mNetworkManager = createMock(INetworkManagementService.class);
173        mPolicyListener = createMock(INetworkPolicyListener.class);
174        mTime = createMock(TrustedTime.class);
175        mConnManager = createMock(IConnectivityManager.class);
176        mNotifManager = createMock(INotificationManager.class);
177
178        mService = new NetworkPolicyManagerService(
179                mServiceContext, mActivityManager, mPowerManager, mStatsService,
180                mNetworkManager, mTime, mPolicyDir);
181        mService.bindConnectivityManager(mConnManager);
182        mService.bindNotificationManager(mNotifManager);
183
184        // RemoteCallbackList needs a binder to use as key
185        expect(mPolicyListener.asBinder()).andReturn(mStubBinder).atLeastOnce();
186        replay();
187        mService.registerListener(mPolicyListener);
188        verifyAndReset();
189
190        // catch IProcessObserver during systemReady()
191        final Capture<IProcessObserver> processObserver = new Capture<IProcessObserver>();
192        mActivityManager.registerProcessObserver(capture(processObserver));
193        expectLastCall().atLeastOnce();
194
195        // catch INetworkManagementEventObserver during systemReady()
196        final Capture<INetworkManagementEventObserver> networkObserver = new Capture<
197                INetworkManagementEventObserver>();
198        mNetworkManager.registerObserver(capture(networkObserver));
199        expectLastCall().atLeastOnce();
200
201        // expect to answer screen status during systemReady()
202        expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
203        expectTime(System.currentTimeMillis());
204
205        replay();
206        mService.systemReady();
207        verifyAndReset();
208
209        mProcessObserver = processObserver.getValue();
210        mNetworkObserver = networkObserver.getValue();
211
212    }
213
214    @Override
215    public void tearDown() throws Exception {
216        for (File file : mPolicyDir.listFiles()) {
217            file.delete();
218        }
219
220        mServiceContext = null;
221        mPolicyDir = null;
222
223        mActivityManager = null;
224        mPowerManager = null;
225        mStatsService = null;
226        mPolicyListener = null;
227        mTime = null;
228
229        mService = null;
230        mProcessObserver = null;
231
232        super.tearDown();
233    }
234
235    @Suppress
236    public void testPolicyChangeTriggersBroadcast() throws Exception {
237        mService.setUidPolicy(UID_A, POLICY_NONE);
238
239        // change background policy and expect broadcast
240        final Future<Intent> backgroundChanged = mServiceContext.nextBroadcastIntent(
241                ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
242
243        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
244
245        backgroundChanged.get();
246    }
247
248    public void testPidForegroundCombined() throws Exception {
249        // push all uid into background
250        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
251        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
252        mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, false);
253        assertFalse(mService.isUidForeground(UID_A));
254        assertFalse(mService.isUidForeground(UID_B));
255
256        // push one of the shared pids into foreground
257        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
258        assertTrue(mService.isUidForeground(UID_A));
259        assertFalse(mService.isUidForeground(UID_B));
260
261        // and swap another uid into foreground
262        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
263        mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, true);
264        assertFalse(mService.isUidForeground(UID_A));
265        assertTrue(mService.isUidForeground(UID_B));
266
267        // push both pid into foreground
268        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
269        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
270        assertTrue(mService.isUidForeground(UID_A));
271
272        // pull one out, should still be foreground
273        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
274        assertTrue(mService.isUidForeground(UID_A));
275
276        // pull final pid out, should now be background
277        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
278        assertFalse(mService.isUidForeground(UID_A));
279    }
280
281    public void testScreenChangesRules() throws Exception {
282        Future<Void> future;
283
284        expectSetUidNetworkRules(UID_A, false);
285        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
286        replay();
287        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
288        future.get();
289        verifyAndReset();
290
291        // push strict policy for foreground uid, verify ALLOW rule
292        expectSetUidNetworkRules(UID_A, false);
293        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
294        replay();
295        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
296        future.get();
297        verifyAndReset();
298
299        // now turn screen off and verify REJECT rule
300        expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
301        expectSetUidNetworkRules(UID_A, true);
302        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
303        replay();
304        mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_OFF));
305        future.get();
306        verifyAndReset();
307
308        // and turn screen back on, verify ALLOW rule restored
309        expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
310        expectSetUidNetworkRules(UID_A, false);
311        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
312        replay();
313        mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON));
314        future.get();
315        verifyAndReset();
316    }
317
318    public void testPolicyNone() throws Exception {
319        Future<Void> future;
320
321        expectSetUidNetworkRules(UID_A, false);
322        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
323        replay();
324        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
325        future.get();
326        verifyAndReset();
327
328        // POLICY_NONE should RULE_ALLOW in foreground
329        expectSetUidNetworkRules(UID_A, false);
330        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
331        replay();
332        mService.setUidPolicy(UID_A, POLICY_NONE);
333        future.get();
334        verifyAndReset();
335
336        // POLICY_NONE should RULE_ALLOW in background
337        expectSetUidNetworkRules(UID_A, false);
338        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
339        replay();
340        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
341        future.get();
342        verifyAndReset();
343    }
344
345    public void testPolicyReject() throws Exception {
346        Future<Void> future;
347
348        // POLICY_REJECT should RULE_ALLOW in background
349        expectSetUidNetworkRules(UID_A, true);
350        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
351        replay();
352        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
353        future.get();
354        verifyAndReset();
355
356        // POLICY_REJECT should RULE_ALLOW in foreground
357        expectSetUidNetworkRules(UID_A, false);
358        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
359        replay();
360        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
361        future.get();
362        verifyAndReset();
363
364        // POLICY_REJECT should RULE_REJECT in background
365        expectSetUidNetworkRules(UID_A, true);
366        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
367        replay();
368        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
369        future.get();
370        verifyAndReset();
371    }
372
373    public void testPolicyRejectAddRemove() throws Exception {
374        Future<Void> future;
375
376        // POLICY_NONE should have RULE_ALLOW in background
377        expectSetUidNetworkRules(UID_A, false);
378        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
379        replay();
380        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
381        mService.setUidPolicy(UID_A, POLICY_NONE);
382        future.get();
383        verifyAndReset();
384
385        // adding POLICY_REJECT should cause RULE_REJECT
386        expectSetUidNetworkRules(UID_A, true);
387        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
388        replay();
389        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
390        future.get();
391        verifyAndReset();
392
393        // removing POLICY_REJECT should return us to RULE_ALLOW
394        expectSetUidNetworkRules(UID_A, false);
395        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
396        replay();
397        mService.setUidPolicy(UID_A, POLICY_NONE);
398        future.get();
399        verifyAndReset();
400    }
401
402    public void testLastCycleBoundaryThisMonth() throws Exception {
403        // assume cycle day of "5th", which should be in same month
404        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
405        final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
406
407        final NetworkPolicy policy = new NetworkPolicy(
408                sTemplateWifi, 5, 1024L, 1024L, SNOOZE_NEVER);
409        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
410        assertTimeEquals(expectedCycle, actualCycle);
411    }
412
413    public void testLastCycleBoundaryLastMonth() throws Exception {
414        // assume cycle day of "20th", which should be in last month
415        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
416        final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
417
418        final NetworkPolicy policy = new NetworkPolicy(
419                sTemplateWifi, 20, 1024L, 1024L, SNOOZE_NEVER);
420        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
421        assertTimeEquals(expectedCycle, actualCycle);
422    }
423
424    public void testLastCycleBoundaryThisMonthFebruary() throws Exception {
425        // assume cycle day of "30th" in february; should go to january
426        final long currentTime = parseTime("2007-02-14T00:00:00.000Z");
427        final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
428
429        final NetworkPolicy policy = new NetworkPolicy(
430                sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER);
431        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
432        assertTimeEquals(expectedCycle, actualCycle);
433    }
434
435    public void testLastCycleBoundaryLastMonthFebruary() throws Exception {
436        // assume cycle day of "30th" in february, which should clamp
437        final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
438        final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
439
440        final NetworkPolicy policy = new NetworkPolicy(
441                sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER);
442        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
443        assertTimeEquals(expectedCycle, actualCycle);
444    }
445
446    public void testNextCycleSane() throws Exception {
447        final NetworkPolicy policy = new NetworkPolicy(
448                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER);
449        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
450
451        // walk forwards, ensuring that cycle boundaries don't get stuck
452        long currentCycle = computeNextCycleBoundary(parseTime("2011-08-01T00:00:00.000Z"), policy);
453        for (int i = 0; i < 128; i++) {
454            long nextCycle = computeNextCycleBoundary(currentCycle, policy);
455            assertEqualsFuzzy(DAY_IN_MILLIS * 30, nextCycle - currentCycle, DAY_IN_MILLIS * 3);
456            assertUnique(seen, nextCycle);
457            currentCycle = nextCycle;
458        }
459    }
460
461    public void testLastCycleSane() throws Exception {
462        final NetworkPolicy policy = new NetworkPolicy(
463                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER);
464        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
465
466        // walk backwards, ensuring that cycle boundaries look sane
467        long currentCycle = computeLastCycleBoundary(parseTime("2011-08-04T00:00:00.000Z"), policy);
468        for (int i = 0; i < 128; i++) {
469            long lastCycle = computeLastCycleBoundary(currentCycle, policy);
470            assertEqualsFuzzy(DAY_IN_MILLIS * 30, currentCycle - lastCycle, DAY_IN_MILLIS * 3);
471            assertUnique(seen, lastCycle);
472            currentCycle = lastCycle;
473        }
474    }
475
476    public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
477        long elapsedRealtime = 0;
478        NetworkState[] state = null;
479        NetworkStats stats = null;
480        Future<Void> future;
481
482        final long TIME_FEB_15 = 1171497600000L;
483        final long TIME_MAR_10 = 1173484800000L;
484        final int CYCLE_DAY = 15;
485
486        // first, pretend that wifi network comes online. no policy active,
487        // which means we shouldn't push limit to interface.
488        state = new NetworkState[] { buildWifi() };
489        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
490        expectTime(TIME_MAR_10 + elapsedRealtime);
491        expectClearNotifications();
492        future = expectMeteredIfacesChanged();
493
494        replay();
495        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
496        future.get();
497        verifyAndReset();
498
499        // now change cycle to be on 15th, and test in early march, to verify we
500        // pick cycle day in previous month.
501        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
502        expectTime(TIME_MAR_10 + elapsedRealtime);
503
504        // pretend that 512 bytes total have happened
505        stats = new NetworkStats(elapsedRealtime, 1)
506                .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 256L, 2L, 256L, 2L, 11);
507        expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
508                .andReturn(stats).atLeastOnce();
509
510        // TODO: consider making strongly ordered mock
511        expectRemoveInterfaceQuota(TEST_IFACE);
512        expectSetInterfaceQuota(TEST_IFACE, 1536L);
513        expectRemoveInterfaceAlert(TEST_IFACE);
514        expectSetInterfaceAlert(TEST_IFACE, 512L);
515
516        expectClearNotifications();
517        future = expectMeteredIfacesChanged(TEST_IFACE);
518
519        replay();
520        setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1024L, 2048L, SNOOZE_NEVER));
521        future.get();
522        verifyAndReset();
523    }
524
525    public void testUidRemovedPolicyCleared() throws Exception {
526        Future<Void> future;
527
528        // POLICY_REJECT should RULE_REJECT in background
529        expectSetUidNetworkRules(UID_A, true);
530        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
531        replay();
532        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
533        future.get();
534        verifyAndReset();
535
536        // uninstall should clear RULE_REJECT
537        expectSetUidNetworkRules(UID_A, false);
538        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
539        replay();
540        final Intent intent = new Intent(ACTION_UID_REMOVED);
541        intent.putExtra(EXTRA_UID, UID_A);
542        mServiceContext.sendBroadcast(intent);
543        future.get();
544        verifyAndReset();
545    }
546
547    public void testOverWarningLimitNotification() throws Exception {
548        long elapsedRealtime = 0;
549        long currentTime = 0;
550        NetworkState[] state = null;
551        NetworkStats stats = null;
552        Future<Void> future;
553        Capture<String> tag;
554
555        final long TIME_FEB_15 = 1171497600000L;
556        final long TIME_MAR_10 = 1173484800000L;
557        final int CYCLE_DAY = 15;
558
559        // assign wifi policy
560        elapsedRealtime = 0;
561        currentTime = TIME_MAR_10 + elapsedRealtime;
562        state = new NetworkState[] {};
563
564        {
565            expectTime(currentTime);
566            expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
567
568            expectClearNotifications();
569            future = expectMeteredIfacesChanged();
570
571            replay();
572            setNetworkPolicies(
573                    new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1024L, 2048L, SNOOZE_NEVER));
574            future.get();
575            verifyAndReset();
576        }
577
578        // bring up wifi network
579        elapsedRealtime += MINUTE_IN_MILLIS;
580        currentTime = TIME_MAR_10 + elapsedRealtime;
581        stats = new NetworkStats(elapsedRealtime, 1)
582                .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0);
583        state = new NetworkState[] { buildWifi() };
584
585        {
586            expectTime(currentTime);
587            expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
588            expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
589                    .andReturn(stats).atLeastOnce();
590
591            expectRemoveInterfaceQuota(TEST_IFACE);
592            expectSetInterfaceQuota(TEST_IFACE, 2048L);
593            expectRemoveInterfaceAlert(TEST_IFACE);
594            expectSetInterfaceAlert(TEST_IFACE, 1024L);
595
596            expectClearNotifications();
597            future = expectMeteredIfacesChanged(TEST_IFACE);
598
599            replay();
600            mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
601            future.get();
602            verifyAndReset();
603        }
604
605        // go over warning, which should kick notification
606        elapsedRealtime += MINUTE_IN_MILLIS;
607        currentTime = TIME_MAR_10 + elapsedRealtime;
608        stats = new NetworkStats(elapsedRealtime, 1)
609                .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 1536L, 15L, 0L, 0L, 11);
610
611        {
612            expectTime(currentTime);
613            expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
614                    .andReturn(stats).atLeastOnce();
615
616            expectForceUpdate();
617            expectClearNotifications();
618            tag = expectEnqueueNotification();
619
620            replay();
621            mNetworkObserver.limitReached(null, TEST_IFACE);
622            assertNotificationType(TYPE_WARNING, tag.getValue());
623            verifyAndReset();
624        }
625
626        // go over limit, which should kick notification and dialog
627        elapsedRealtime += MINUTE_IN_MILLIS;
628        currentTime = TIME_MAR_10 + elapsedRealtime;
629        stats = new NetworkStats(elapsedRealtime, 1)
630                .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 5120L, 512L, 0L, 0L, 22);
631
632        {
633            expectTime(currentTime);
634            expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
635                    .andReturn(stats).atLeastOnce();
636
637            expectForceUpdate();
638            expectClearNotifications();
639            tag = expectEnqueueNotification();
640
641            replay();
642            mNetworkObserver.limitReached(null, TEST_IFACE);
643            assertNotificationType(TYPE_LIMIT, tag.getValue());
644            verifyAndReset();
645        }
646
647        // now snooze policy, which should remove quota
648        elapsedRealtime += MINUTE_IN_MILLIS;
649        currentTime = TIME_MAR_10 + elapsedRealtime;
650
651        {
652            expectTime(currentTime);
653            expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
654            expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
655                    .andReturn(stats).atLeastOnce();
656
657            expectRemoveInterfaceQuota(TEST_IFACE);
658            expectRemoveInterfaceAlert(TEST_IFACE);
659
660            expectClearNotifications();
661            tag = expectEnqueueNotification();
662            future = expectMeteredIfacesChanged();
663
664            replay();
665            mService.snoozePolicy(sTemplateWifi);
666            future.get();
667            assertNotificationType(TYPE_LIMIT_SNOOZED, tag.getValue());
668            verifyAndReset();
669        }
670    }
671
672    private static long parseTime(String time) {
673        final Time result = new Time();
674        result.parse3339(time);
675        return result.toMillis(true);
676    }
677
678    private void setNetworkPolicies(NetworkPolicy... policies) {
679        mService.setNetworkPolicies(policies);
680    }
681
682    private static NetworkState buildWifi() {
683        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
684        info.setDetailedState(DetailedState.CONNECTED, null, null);
685        final LinkProperties prop = new LinkProperties();
686        prop.setInterfaceName(TEST_IFACE);
687        return new NetworkState(info, prop, null);
688    }
689
690    private void expectTime(long currentTime) throws Exception {
691        expect(mTime.forceRefresh()).andReturn(false).anyTimes();
692        expect(mTime.hasCache()).andReturn(true).anyTimes();
693        expect(mTime.currentTimeMillis()).andReturn(currentTime).anyTimes();
694        expect(mTime.getCacheAge()).andReturn(0L).anyTimes();
695        expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
696    }
697
698    private void expectForceUpdate() throws Exception {
699        mStatsService.forceUpdate();
700        expectLastCall().atLeastOnce();
701    }
702
703    private void expectClearNotifications() throws Exception {
704        mNotifManager.cancelNotificationWithTag(isA(String.class), isA(String.class), anyInt());
705        expectLastCall().anyTimes();
706    }
707
708    private Capture<String> expectEnqueueNotification() throws Exception {
709        final Capture<String> tag = new Capture<String>();
710        mNotifManager.enqueueNotificationWithTag(isA(String.class), capture(tag), anyInt(),
711                isA(Notification.class), isA(int[].class));
712        return tag;
713    }
714
715    private void expectSetInterfaceQuota(String iface, long quotaBytes) throws Exception {
716        mNetworkManager.setInterfaceQuota(iface, quotaBytes);
717        expectLastCall().atLeastOnce();
718    }
719
720    private void expectRemoveInterfaceQuota(String iface) throws Exception {
721        mNetworkManager.removeInterfaceQuota(iface);
722        expectLastCall().atLeastOnce();
723    }
724
725    private void expectSetInterfaceAlert(String iface, long alertBytes) throws Exception {
726        mNetworkManager.setInterfaceAlert(iface, alertBytes);
727        expectLastCall().atLeastOnce();
728    }
729
730    private void expectRemoveInterfaceAlert(String iface) throws Exception {
731        mNetworkManager.removeInterfaceAlert(iface);
732        expectLastCall().atLeastOnce();
733    }
734
735    private void expectSetUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces)
736            throws Exception {
737        mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
738        expectLastCall().atLeastOnce();
739    }
740
741    private Future<Void> expectRulesChanged(int uid, int policy) throws Exception {
742        final FutureAnswer future = new FutureAnswer();
743        mPolicyListener.onUidRulesChanged(eq(uid), eq(policy));
744        expectLastCall().andAnswer(future);
745        return future;
746    }
747
748    private Future<Void> expectMeteredIfacesChanged(String... ifaces) throws Exception {
749        final FutureAnswer future = new FutureAnswer();
750        mPolicyListener.onMeteredIfacesChanged(aryEq(ifaces));
751        expectLastCall().andAnswer(future);
752        return future;
753    }
754
755    private static class FutureAnswer extends AbstractFuture<Void> implements IAnswer<Void> {
756        @Override
757        public Void get() throws InterruptedException, ExecutionException {
758            try {
759                return get(5, TimeUnit.SECONDS);
760            } catch (TimeoutException e) {
761                throw new RuntimeException(e);
762            }
763        }
764
765        @Override
766        public Void answer() {
767            set(null);
768            return null;
769        }
770    }
771
772    private static void assertTimeEquals(long expected, long actual) {
773        if (expected != actual) {
774            fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual));
775        }
776    }
777
778    private static String formatTime(long millis) {
779        final Time time = new Time(Time.TIMEZONE_UTC);
780        time.set(millis);
781        return time.format3339(false);
782    }
783
784    private static void assertEqualsFuzzy(long expected, long actual, long fuzzy) {
785        final long low = expected - fuzzy;
786        final long high = expected + fuzzy;
787        if (actual < low || actual > high) {
788            fail("value " + actual + " is outside [" + low + "," + high + "]");
789        }
790    }
791
792    private static void assertUnique(LinkedHashSet<Long> seen, Long value) {
793        if (!seen.add(value)) {
794            fail("found duplicate time " + value + " in series " + seen.toString());
795        }
796    }
797
798    private static void assertNotificationType(int expected, String actualTag) {
799        assertEquals(
800                Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1));
801    }
802
803    private void replay() {
804        EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
805                mNetworkManager, mTime, mConnManager, mNotifManager);
806    }
807
808    private void verifyAndReset() {
809        EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
810                mNetworkManager, mTime, mConnManager, mNotifManager);
811        EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
812                mNetworkManager, mTime, mConnManager, mNotifManager);
813    }
814}
815