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