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