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