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