NetworkPolicyManagerServiceTest.java revision e88729d3a106807a094ed15891e0d2ef4fb7f73d
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.net.ConnectivityManager.CONNECTIVITY_ACTION;
20import static android.net.ConnectivityManager.TYPE_WIFI;
21import static android.net.NetworkPolicy.LIMIT_DISABLED;
22import static android.net.NetworkPolicy.WARNING_DISABLED;
23import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
24import static android.net.NetworkPolicyManager.POLICY_NONE;
25import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
26import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
27import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
28import static android.net.NetworkPolicyManager.uidPoliciesToString;
29import static android.net.TrafficStats.KB_IN_BYTES;
30import static android.net.TrafficStats.MB_IN_BYTES;
31import static android.text.format.DateUtils.DAY_IN_MILLIS;
32import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
33import static android.text.format.Time.TIMEZONE_UTC;
34
35import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
36import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
37import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
38
39import static org.junit.Assert.assertEquals;
40import static org.junit.Assert.assertFalse;
41import static org.junit.Assert.assertNotNull;
42import static org.junit.Assert.assertNull;
43import static org.junit.Assert.assertTrue;
44import static org.junit.Assert.fail;
45import static org.mockito.Matchers.any;
46import static org.mockito.Matchers.anyBoolean;
47import static org.mockito.Matchers.anyInt;
48import static org.mockito.Matchers.anyLong;
49import static org.mockito.Matchers.anyString;
50import static org.mockito.Matchers.eq;
51import static org.mockito.Matchers.isA;
52import static org.mockito.Mockito.atLeastOnce;
53import static org.mockito.Mockito.doAnswer;
54import static org.mockito.Mockito.mock;
55import static org.mockito.Mockito.verify;
56import static org.mockito.Mockito.when;
57
58import android.app.ActivityManager;
59import android.app.IActivityManager;
60import android.app.INotificationManager;
61import android.app.IUidObserver;
62import android.app.Notification;
63import android.app.usage.UsageStatsManagerInternal;
64import android.content.Context;
65import android.content.Intent;
66import android.content.pm.ApplicationInfo;
67import android.content.pm.PackageInfo;
68import android.content.pm.PackageManager;
69import android.content.pm.Signature;
70import android.net.IConnectivityManager;
71import android.net.INetworkManagementEventObserver;
72import android.net.INetworkPolicyListener;
73import android.net.INetworkStatsService;
74import android.net.LinkProperties;
75import android.net.NetworkInfo;
76import android.net.NetworkInfo.DetailedState;
77import android.net.NetworkPolicy;
78import android.net.NetworkState;
79import android.net.NetworkStats;
80import android.net.NetworkTemplate;
81import android.os.Binder;
82import android.os.INetworkManagementService;
83import android.os.PowerManagerInternal;
84import android.os.UserHandle;
85import android.support.test.InstrumentationRegistry;
86import android.support.test.runner.AndroidJUnit4;
87import android.text.TextUtils;
88import android.text.format.Time;
89import android.util.Log;
90import android.util.TrustedTime;
91
92import com.android.server.net.NetworkPolicyManagerInternal;
93import com.android.server.net.NetworkPolicyManagerService;
94
95import libcore.io.IoUtils;
96import libcore.io.Streams;
97
98import com.google.common.util.concurrent.AbstractFuture;
99
100import org.junit.After;
101import org.junit.Before;
102import org.junit.BeforeClass;
103import org.junit.Rule;
104import org.junit.Test;
105import org.junit.rules.MethodRule;
106import org.junit.runner.RunWith;
107import org.junit.runners.model.FrameworkMethod;
108import org.junit.runners.model.Statement;
109import org.mockito.ArgumentCaptor;
110import org.mockito.Mock;
111import org.mockito.MockitoAnnotations;
112import org.mockito.invocation.InvocationOnMock;
113import org.mockito.stubbing.Answer;
114
115import java.io.File;
116import java.io.FileOutputStream;
117import java.io.InputStream;
118import java.io.OutputStream;
119import java.lang.annotation.Annotation;
120import java.lang.annotation.ElementType;
121import java.lang.annotation.Retention;
122import java.lang.annotation.RetentionPolicy;
123import java.lang.annotation.Target;
124import java.util.Arrays;
125import java.util.LinkedHashSet;
126import java.util.List;
127import java.util.concurrent.CountDownLatch;
128import java.util.concurrent.ExecutionException;
129import java.util.concurrent.Future;
130import java.util.concurrent.TimeUnit;
131import java.util.concurrent.TimeoutException;
132import java.util.stream.Collectors;
133
134/**
135 * Tests for {@link NetworkPolicyManagerService}.
136 */
137@RunWith(AndroidJUnit4.class)
138public class NetworkPolicyManagerServiceTest {
139    private static final String TAG = "NetworkPolicyManagerServiceTest";
140
141    private static final long TEST_START = 1194220800000L;
142    private static final String TEST_IFACE = "test0";
143    private static final String TEST_SSID = "AndroidAP";
144
145    private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi(TEST_SSID);
146
147    /**
148     * Path on assets where files used by {@link NetPolicyXml} are located.
149     */
150    private static final String NETPOLICY_DIR = "NetworkPolicyManagerServiceTest/netpolicy";
151
152    private BroadcastInterceptingContext mServiceContext;
153    private File mPolicyDir;
154
155    /**
156     * Relative path of the XML file that will be used as {@code netpolicy.xml}.
157     *
158     * <p>Typically set through a {@link NetPolicyXml} annotation in the test method.
159     */
160    private String mNetpolicyXml;
161
162
163    private @Mock IActivityManager mActivityManager;
164    private @Mock INetworkStatsService mStatsService;
165    private @Mock INetworkManagementService mNetworkManager;
166    private @Mock TrustedTime mTime;
167    private @Mock IConnectivityManager mConnManager;
168    private @Mock INotificationManager mNotifManager;
169    private @Mock PackageManager mPackageManager;
170
171    private IUidObserver mUidObserver;
172    private INetworkManagementEventObserver mNetworkObserver;
173
174    private NetworkPolicyListenerAnswer mPolicyListener;
175    private NetworkPolicyManagerService mService;
176
177    private long mStartTime;
178    private long mElapsedRealtime;
179
180    private static final int USER_ID = 0;
181
182    private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 4;
183    private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 8;
184    private static final int APP_ID_C = android.os.Process.FIRST_APPLICATION_UID + 15;
185    private static final int APP_ID_D = android.os.Process.FIRST_APPLICATION_UID + 16;
186    private static final int APP_ID_E = android.os.Process.FIRST_APPLICATION_UID + 23;
187    private static final int APP_ID_F = android.os.Process.FIRST_APPLICATION_UID + 42;
188
189    private static final int UID_A = UserHandle.getUid(USER_ID, APP_ID_A);
190    private static final int UID_B = UserHandle.getUid(USER_ID, APP_ID_B);
191    private static final int UID_C = UserHandle.getUid(USER_ID, APP_ID_C);
192    private static final int UID_D = UserHandle.getUid(USER_ID, APP_ID_D);
193    private static final int UID_E = UserHandle.getUid(USER_ID, APP_ID_E);
194    private static final int UID_F = UserHandle.getUid(USER_ID, APP_ID_F);
195
196    private static final String PKG_NAME_A = "name.is.A,pkg.A";
197
198    public final @Rule NetPolicyMethodRule mNetPolicyXmlRule = new NetPolicyMethodRule();
199
200    @BeforeClass
201    public static void registerLocalServices() {
202        addLocalServiceMock(PowerManagerInternal.class);
203        addLocalServiceMock(DeviceIdleController.LocalService.class);
204        final UsageStatsManagerInternal usageStats =
205                addLocalServiceMock(UsageStatsManagerInternal.class);
206        when(usageStats.getIdleUidsForUser(anyInt())).thenReturn(new int[]{});
207    }
208
209    @Before
210    public void callSystemReady() throws Exception {
211        MockitoAnnotations.initMocks(this);
212
213        final Context context = InstrumentationRegistry.getContext();
214
215        setCurrentTimeMillis(TEST_START);
216
217        // intercept various broadcasts, and pretend that uids have packages
218        mServiceContext = new BroadcastInterceptingContext(context) {
219            @Override
220            public PackageManager getPackageManager() {
221                return mPackageManager;
222            }
223
224            @Override
225            public void startActivity(Intent intent) {
226                // ignored
227            }
228        };
229
230        setNetpolicyXml(context);
231
232        doAnswer(new Answer<Void>() {
233
234            @Override
235            public Void answer(InvocationOnMock invocation) throws Throwable {
236                mUidObserver = (IUidObserver) invocation.getArguments()[0];
237                Log.d(TAG, "set mUidObserver to " + mUidObserver);
238                return null;
239            }
240        }).when(mActivityManager).registerUidObserver(any(), anyInt());
241
242        mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
243                mNetworkManager, mTime, mPolicyDir, true);
244        mService.bindConnectivityManager(mConnManager);
245        mService.bindNotificationManager(mNotifManager);
246        mPolicyListener = new NetworkPolicyListenerAnswer(mService);
247
248        // Sets some common expectations.
249        when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenAnswer(
250                new Answer<PackageInfo>() {
251
252                    @Override
253                    public PackageInfo answer(InvocationOnMock invocation) throws Throwable {
254                        final String packageName = (String) invocation.getArguments()[0];
255                        final PackageInfo info = new PackageInfo();
256                        final Signature signature;
257                        if ("android".equals(packageName)) {
258                            signature = new Signature("F00D");
259                        } else {
260                            signature = new Signature("DEAD");
261                        }
262                        info.signatures = new Signature[] {
263                            signature
264                        };
265                        return info;
266                    }
267                });
268        when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
269                .thenReturn(new ApplicationInfo());
270        when(mPackageManager.getPackagesForUid(UID_A)).thenReturn(new String[] {PKG_NAME_A});
271        when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true);
272        expectCurrentTime();
273
274        // Prepare NPMS.
275        mService.systemReady();
276
277        // catch INetworkManagementEventObserver during systemReady()
278        ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
279              ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
280        verify(mNetworkManager).registerObserver(networkObserver.capture());
281        mNetworkObserver = networkObserver.getValue();
282    }
283
284    @After
285    public void removeFiles() throws Exception {
286        for (File file : mPolicyDir.listFiles()) {
287            file.delete();
288        }
289    }
290
291    @After
292    public void unregisterLocalServices() throws Exception {
293        // Registered by NetworkPolicyManagerService's constructor.
294        LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
295    }
296
297    @Test
298    @NetPolicyXml("restrict-background-lists-whitelist-format.xml")
299    public void testRestrictBackgroundLists_whitelistFormat() throws Exception {
300        // UIds that are whitelisted
301        final int[] whitelisted = mService.getRestrictBackgroundWhitelistedUids();
302        assertContainsInAnyOrder(whitelisted, UID_A, UID_B, UID_C);
303        assertUidPolicy(UID_A, POLICY_NONE);
304        assertUidPolicy(UID_B, POLICY_NONE);
305        assertUidPolicy(UID_C, POLICY_NONE);
306
307        // UIDs that are blacklisted
308        assertUidPolicy(UID_D, POLICY_NONE);
309        assertUidPolicy(UID_E, POLICY_REJECT_METERED_BACKGROUND);
310        assertUidPolicy(UID_F, POLICY_ALLOW_BACKGROUND_BATTERY_SAVE);
311    }
312
313    // NOTE: testPolicyChangeTriggersListener() and testUidForeground() are too superficial, they
314    // don't check for side-effects (like calls to NetworkManagementService) neither cover all
315    // different modes (Data Saver, Battery Saver, Doze, App idle, etc...).
316    // These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests.
317
318    @Test
319    public void testPolicyChangeTriggersListener() throws Exception {
320        mPolicyListener.expect().onRestrictBackgroundBlacklistChanged(anyInt(), anyBoolean());
321
322        mService.setUidPolicy(APP_ID_A, POLICY_NONE);
323        mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
324
325        mPolicyListener.waitAndVerify().onRestrictBackgroundBlacklistChanged(APP_ID_A, true);
326    }
327
328    @Test
329    public void testUidForeground() throws Exception {
330        // push all uids into background
331        mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE);
332        mUidObserver.onUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE);
333        assertFalse(mService.isUidForeground(UID_A));
334        assertFalse(mService.isUidForeground(UID_B));
335
336        // push one of the uids into foreground
337        mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP);
338        assertTrue(mService.isUidForeground(UID_A));
339        assertFalse(mService.isUidForeground(UID_B));
340
341        // and swap another uid into foreground
342        mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE);
343        mUidObserver.onUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP);
344        assertFalse(mService.isUidForeground(UID_A));
345        assertTrue(mService.isUidForeground(UID_B));
346    }
347
348    @Test
349    public void testLastCycleBoundaryThisMonth() throws Exception {
350        // assume cycle day of "5th", which should be in same month
351        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
352        final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
353
354        final NetworkPolicy policy = new NetworkPolicy(
355                sTemplateWifi, 5, TIMEZONE_UTC, 1024L, 1024L, false);
356        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
357        assertTimeEquals(expectedCycle, actualCycle);
358    }
359
360    @Test
361    public void testLastCycleBoundaryLastMonth() throws Exception {
362        // assume cycle day of "20th", which should be in last month
363        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
364        final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
365
366        final NetworkPolicy policy = new NetworkPolicy(
367                sTemplateWifi, 20, TIMEZONE_UTC, 1024L, 1024L, false);
368        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
369        assertTimeEquals(expectedCycle, actualCycle);
370    }
371
372    @Test
373    public void testLastCycleBoundaryThisMonthFebruary() throws Exception {
374        // assume cycle day of "30th" in february; should go to january
375        final long currentTime = parseTime("2007-02-14T00:00:00.000Z");
376        final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
377
378        final NetworkPolicy policy = new NetworkPolicy(
379                sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false);
380        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
381        assertTimeEquals(expectedCycle, actualCycle);
382    }
383
384    @Test
385    public void testLastCycleBoundaryLastMonthFebruary() throws Exception {
386        // assume cycle day of "30th" in february, which should clamp
387        final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
388        final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
389
390        final NetworkPolicy policy = new NetworkPolicy(
391                sTemplateWifi, 30, TIMEZONE_UTC, 1024L, 1024L, false);
392        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
393        assertTimeEquals(expectedCycle, actualCycle);
394    }
395
396    @Test
397    public void testCycleBoundaryLeapYear() throws Exception {
398        final NetworkPolicy policy = new NetworkPolicy(
399                sTemplateWifi, 29, TIMEZONE_UTC, 1024L, 1024L, false);
400
401        assertTimeEquals(parseTime("2012-01-29T00:00:00.000Z"),
402                computeNextCycleBoundary(parseTime("2012-01-14T00:00:00.000Z"), policy));
403        assertTimeEquals(parseTime("2012-02-29T00:00:00.000Z"),
404                computeNextCycleBoundary(parseTime("2012-02-14T00:00:00.000Z"), policy));
405        assertTimeEquals(parseTime("2012-02-29T00:00:00.000Z"),
406                computeLastCycleBoundary(parseTime("2012-03-14T00:00:00.000Z"), policy));
407        assertTimeEquals(parseTime("2012-03-29T00:00:00.000Z"),
408                computeNextCycleBoundary(parseTime("2012-03-14T00:00:00.000Z"), policy));
409
410        assertTimeEquals(parseTime("2007-01-29T00:00:00.000Z"),
411                computeNextCycleBoundary(parseTime("2007-01-14T00:00:00.000Z"), policy));
412        assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"),
413                computeNextCycleBoundary(parseTime("2007-02-14T00:00:00.000Z"), policy));
414        assertTimeEquals(parseTime("2007-02-28T23:59:59.000Z"),
415                computeLastCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy));
416        assertTimeEquals(parseTime("2007-03-29T00:00:00.000Z"),
417                computeNextCycleBoundary(parseTime("2007-03-14T00:00:00.000Z"), policy));
418    }
419
420    @Test
421    public void testNextCycleTimezoneAfterUtc() throws Exception {
422        // US/Central is UTC-6
423        final NetworkPolicy policy = new NetworkPolicy(
424                sTemplateWifi, 10, "US/Central", 1024L, 1024L, false);
425        assertTimeEquals(parseTime("2012-01-10T06:00:00.000Z"),
426                computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy));
427    }
428
429    @Test
430    public void testNextCycleTimezoneBeforeUtc() throws Exception {
431        // Israel is UTC+2
432        final NetworkPolicy policy = new NetworkPolicy(
433                sTemplateWifi, 10, "Israel", 1024L, 1024L, false);
434        assertTimeEquals(parseTime("2012-01-09T22:00:00.000Z"),
435                computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy));
436    }
437
438    @Test
439    public void testNextCycleSane() throws Exception {
440        final NetworkPolicy policy = new NetworkPolicy(
441                sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false);
442        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
443
444        // walk forwards, ensuring that cycle boundaries don't get stuck
445        long currentCycle = computeNextCycleBoundary(parseTime("2011-08-01T00:00:00.000Z"), policy);
446        for (int i = 0; i < 128; i++) {
447            long nextCycle = computeNextCycleBoundary(currentCycle, policy);
448            assertEqualsFuzzy(DAY_IN_MILLIS * 30, nextCycle - currentCycle, DAY_IN_MILLIS * 3);
449            assertUnique(seen, nextCycle);
450            currentCycle = nextCycle;
451        }
452    }
453
454    @Test
455    public void testLastCycleSane() throws Exception {
456        final NetworkPolicy policy = new NetworkPolicy(
457                sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false);
458        final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
459
460        // walk backwards, ensuring that cycle boundaries look sane
461        long currentCycle = computeLastCycleBoundary(parseTime("2011-08-04T00:00:00.000Z"), policy);
462        for (int i = 0; i < 128; i++) {
463            long lastCycle = computeLastCycleBoundary(currentCycle, policy);
464            assertEqualsFuzzy(DAY_IN_MILLIS * 30, currentCycle - lastCycle, DAY_IN_MILLIS * 3);
465            assertUnique(seen, lastCycle);
466            currentCycle = lastCycle;
467        }
468    }
469
470    @Test
471    public void testCycleTodayJanuary() throws Exception {
472        final NetworkPolicy policy = new NetworkPolicy(
473                sTemplateWifi, 14, "US/Pacific", 1024L, 1024L, false);
474
475        assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"),
476                computeNextCycleBoundary(parseTime("2013-01-13T23:59:59.000-08:00"), policy));
477        assertTimeEquals(parseTime("2013-02-14T00:00:00.000-08:00"),
478                computeNextCycleBoundary(parseTime("2013-01-14T00:00:01.000-08:00"), policy));
479        assertTimeEquals(parseTime("2013-02-14T00:00:00.000-08:00"),
480                computeNextCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy));
481
482        assertTimeEquals(parseTime("2012-12-14T00:00:00.000-08:00"),
483                computeLastCycleBoundary(parseTime("2013-01-13T23:59:59.000-08:00"), policy));
484        assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"),
485                computeLastCycleBoundary(parseTime("2013-01-14T00:00:01.000-08:00"), policy));
486        assertTimeEquals(parseTime("2013-01-14T00:00:00.000-08:00"),
487                computeLastCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy));
488    }
489
490    @Test
491    public void testLastCycleBoundaryDST() throws Exception {
492        final long currentTime = parseTime("1989-01-02T07:30:00.000");
493        final long expectedCycle = parseTime("1988-12-03T02:00:00.000Z");
494
495        final NetworkPolicy policy = new NetworkPolicy(
496                sTemplateWifi, 3, "America/Argentina/Buenos_Aires", 1024L, 1024L, false);
497        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
498        assertTimeEquals(expectedCycle, actualCycle);
499    }
500
501    @Test
502    public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
503        NetworkState[] state = null;
504        NetworkStats stats = null;
505
506        final long TIME_FEB_15 = 1171497600000L;
507        final long TIME_MAR_10 = 1173484800000L;
508        final int CYCLE_DAY = 15;
509
510        setCurrentTimeMillis(TIME_MAR_10);
511
512        // first, pretend that wifi network comes online. no policy active,
513        // which means we shouldn't push limit to interface.
514        state = new NetworkState[] { buildWifi() };
515        when(mConnManager.getAllNetworkState()).thenReturn(state);
516        expectCurrentTime();
517
518        mPolicyListener.expect().onMeteredIfacesChanged(any());
519        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
520        mPolicyListener.waitAndVerify().onMeteredIfacesChanged(any());
521
522        // now change cycle to be on 15th, and test in early march, to verify we
523        // pick cycle day in previous month.
524        when(mConnManager.getAllNetworkState()).thenReturn(state);
525        expectCurrentTime();
526
527        // pretend that 512 bytes total have happened
528        stats = new NetworkStats(getElapsedRealtime(), 1)
529                .addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L);
530        when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
531                .thenReturn(stats.getTotalBytes());
532
533        mPolicyListener.expect().onMeteredIfacesChanged(any());
534        setNetworkPolicies(new NetworkPolicy(
535                sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
536        mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE}));
537
538        // TODO: consider making strongly ordered mock
539        verifyPolicyDataEnable(TYPE_WIFI, true);
540        verifyRemoveInterfaceQuota(TEST_IFACE);
541        verifySetInterfaceQuota(TEST_IFACE, (2 * MB_IN_BYTES) - 512);
542    }
543
544    @Test
545    public void testOverWarningLimitNotification() throws Exception {
546        NetworkState[] state = null;
547        NetworkStats stats = null;
548        Future<String> tagFuture = null;
549
550        final long TIME_FEB_15 = 1171497600000L;
551        final long TIME_MAR_10 = 1173484800000L;
552        final int CYCLE_DAY = 15;
553
554        setCurrentTimeMillis(TIME_MAR_10);
555
556        // assign wifi policy
557        state = new NetworkState[] {};
558        stats = new NetworkStats(getElapsedRealtime(), 1)
559                .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
560
561        {
562            expectCurrentTime();
563            when(mConnManager.getAllNetworkState()).thenReturn(state);
564            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
565                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
566
567            mPolicyListener.expect().onMeteredIfacesChanged(any());
568            setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1
569                    * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
570            mPolicyListener.waitAndVerify().onMeteredIfacesChanged(any());
571            verifyPolicyDataEnable(TYPE_WIFI, true);
572        }
573
574        // bring up wifi network
575        incrementCurrentTime(MINUTE_IN_MILLIS);
576        state = new NetworkState[] { buildWifi() };
577        stats = new NetworkStats(getElapsedRealtime(), 1)
578                .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
579
580        {
581            expectCurrentTime();
582            when(mConnManager.getAllNetworkState()).thenReturn(state);
583            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
584                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
585
586            mPolicyListener.expect().onMeteredIfacesChanged(any());
587            mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
588            mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE}));
589
590            verifyPolicyDataEnable(TYPE_WIFI, true);
591            verifyRemoveInterfaceQuota(TEST_IFACE);
592            verifySetInterfaceQuota(TEST_IFACE, 2 * MB_IN_BYTES);
593        }
594
595        // go over warning, which should kick notification
596        incrementCurrentTime(MINUTE_IN_MILLIS);
597        stats = new NetworkStats(getElapsedRealtime(), 1)
598                .addIfaceValues(TEST_IFACE, 1536 * KB_IN_BYTES, 15L, 0L, 0L);
599
600        {
601            expectCurrentTime();
602            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
603                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
604            tagFuture = expectEnqueueNotification();
605
606            mNetworkObserver.limitReached(null, TEST_IFACE);
607
608            assertNotificationType(TYPE_WARNING, tagFuture.get());
609            verifyPolicyDataEnable(TYPE_WIFI, true);
610
611        }
612
613        // go over limit, which should kick notification and dialog
614        incrementCurrentTime(MINUTE_IN_MILLIS);
615        stats = new NetworkStats(getElapsedRealtime(), 1)
616                .addIfaceValues(TEST_IFACE, 5 * MB_IN_BYTES, 512L, 0L, 0L);
617
618        {
619            expectCurrentTime();
620            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
621                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
622            tagFuture = expectEnqueueNotification();
623
624            mNetworkObserver.limitReached(null, TEST_IFACE);
625
626            assertNotificationType(TYPE_LIMIT, tagFuture.get());
627            verifyPolicyDataEnable(TYPE_WIFI, false);
628        }
629
630        // now snooze policy, which should remove quota
631        incrementCurrentTime(MINUTE_IN_MILLIS);
632
633        {
634            expectCurrentTime();
635            when(mConnManager.getAllNetworkState()).thenReturn(state);
636            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
637                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
638            tagFuture = expectEnqueueNotification();
639
640            mPolicyListener.expect().onMeteredIfacesChanged(any());
641            mService.snoozeLimit(sTemplateWifi);
642            mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE}));
643
644            assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get());
645            // snoozed interface still has high quota so background data is
646            // still restricted.
647            verifyRemoveInterfaceQuota(TEST_IFACE);
648            verifySetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE);
649            verifyPolicyDataEnable(TYPE_WIFI, true);
650        }
651    }
652
653    @Test
654    public void testMeteredNetworkWithoutLimit() throws Exception {
655        NetworkState[] state = null;
656        NetworkStats stats = null;
657
658        final long TIME_FEB_15 = 1171497600000L;
659        final long TIME_MAR_10 = 1173484800000L;
660        final int CYCLE_DAY = 15;
661
662        setCurrentTimeMillis(TIME_MAR_10);
663
664        // bring up wifi network with metered policy
665        state = new NetworkState[] { buildWifi() };
666        stats = new NetworkStats(getElapsedRealtime(), 1)
667                .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
668
669        {
670            expectCurrentTime();
671            when(mConnManager.getAllNetworkState()).thenReturn(state);
672            when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
673                    currentTimeMillis())).thenReturn(stats.getTotalBytes());
674
675            mPolicyListener.expect().onMeteredIfacesChanged(any());
676            setNetworkPolicies(new NetworkPolicy(
677                    sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED,
678                    true));
679            mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE}));
680
681            verifyPolicyDataEnable(TYPE_WIFI, true);
682            verifyRemoveInterfaceQuota(TEST_IFACE);
683            verifySetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE);
684        }
685    }
686
687    private static long parseTime(String time) {
688        final Time result = new Time();
689        result.parse3339(time);
690        return result.toMillis(true);
691    }
692
693    private void setNetworkPolicies(NetworkPolicy... policies) {
694        mService.setNetworkPolicies(policies);
695    }
696
697    private static NetworkState buildWifi() {
698        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
699        info.setDetailedState(DetailedState.CONNECTED, null, null);
700        final LinkProperties prop = new LinkProperties();
701        prop.setInterfaceName(TEST_IFACE);
702        return new NetworkState(info, prop, null, null, null, TEST_SSID);
703    }
704
705    private void expectCurrentTime() throws Exception {
706        when(mTime.forceRefresh()).thenReturn(false);
707        when(mTime.hasCache()).thenReturn(true);
708        when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis());
709        when(mTime.getCacheAge()).thenReturn(0L);
710        when(mTime.getCacheCertainty()).thenReturn(0L);
711    }
712
713    private Future<String> expectEnqueueNotification() throws Exception {
714        final FutureAnswer<String> futureAnswer = new FutureAnswer<String>(2);
715        doAnswer(futureAnswer).when(mNotifManager).enqueueNotificationWithTag(
716                anyString(), anyString(), anyString() /* capture here (index 2)*/,
717                anyInt(), isA(Notification.class), isA(int[].class), anyInt());
718        return futureAnswer;
719    }
720
721    private void verifySetInterfaceQuota(String iface, long quotaBytes) throws Exception {
722        verify(mNetworkManager, atLeastOnce()).setInterfaceQuota(iface, quotaBytes);
723    }
724
725    private void verifyRemoveInterfaceQuota(String iface) throws Exception {
726        verify(mNetworkManager, atLeastOnce()).removeInterfaceQuota(iface);
727    }
728
729    private Future<Void> verifyPolicyDataEnable(int type, boolean enabled) throws Exception {
730        // TODO: bring back this test
731        return null;
732    }
733
734    private void verifyAdvisePersistThreshold() throws Exception {
735        verify(mStatsService).advisePersistThreshold(anyLong());
736    }
737
738    private static class TestAbstractFuture<T> extends AbstractFuture<T> {
739        @Override
740        public T get() throws InterruptedException, ExecutionException {
741            try {
742                return get(5, TimeUnit.SECONDS);
743            } catch (TimeoutException e) {
744                throw new RuntimeException(e);
745            }
746        }
747    }
748
749    private static class FutureAnswer<T> extends TestAbstractFuture<T> implements Answer<Void> {
750        private final int index;
751
752        FutureAnswer(int index) {
753            this.index = index;
754        }
755        @Override
756        public Void answer(InvocationOnMock invocation) throws Throwable {
757            @SuppressWarnings("unchecked")
758            T captured = (T) invocation.getArguments()[index];
759            set(captured);
760            return null;
761        }
762    }
763
764    private static void assertTimeEquals(long expected, long actual) {
765        if (expected != actual) {
766            fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual));
767        }
768    }
769
770    private static String formatTime(long millis) {
771        final Time time = new Time(Time.TIMEZONE_UTC);
772        time.set(millis);
773        return time.format3339(false);
774    }
775
776    private static void assertEqualsFuzzy(long expected, long actual, long fuzzy) {
777        final long low = expected - fuzzy;
778        final long high = expected + fuzzy;
779        if (actual < low || actual > high) {
780            fail("value " + actual + " is outside [" + low + "," + high + "]");
781        }
782    }
783
784    private static void assertUnique(LinkedHashSet<Long> seen, Long value) {
785        if (!seen.add(value)) {
786            fail("found duplicate time " + value + " in series " + seen.toString());
787        }
788    }
789
790    private static void assertNotificationType(int expected, String actualTag) {
791        assertEquals("notification type mismatch for '" + actualTag +"'",
792                Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1));
793    }
794
795    private void assertUidPolicy(int uid, int expected) {
796        final int actual = mService.getUidPolicy(uid);
797        if (expected != actual) {
798            fail("Wrong policy for UID " + uid + ": expected " + uidPoliciesToString(expected)
799                    + ", actual " + uidPoliciesToString(actual));
800        }
801    }
802
803    // TODO: replace by Truth, Hamcrest, or a similar tool.
804    private void assertContainsInAnyOrder(int[] actual, int...expected) {
805        final StringBuilder errors = new StringBuilder();
806        if (actual.length != expected.length) {
807            errors.append("\tsize does not match\n");
808        }
809        final List<Integer> actualList =
810                Arrays.stream(actual).boxed().collect(Collectors.<Integer>toList());
811        final List<Integer> expectedList =
812                Arrays.stream(expected).boxed().collect(Collectors.<Integer>toList());
813        if (!actualList.containsAll(expectedList)) {
814            errors.append("\tmissing elements on actual list\n");
815        }
816        if (!expectedList.containsAll(actualList)) {
817            errors.append("\tmissing elements on expected list\n");
818        }
819        if (errors.length() > 0) {
820            fail("assertContainsInAnyOrder(expected=" + Arrays.toString(expected)
821                    + ", actual=" + Arrays.toString(actual) +") failed: \n" + errors);
822        }
823    }
824
825    private long getElapsedRealtime() {
826        return mElapsedRealtime;
827    }
828
829    private void setCurrentTimeMillis(long currentTimeMillis) {
830        mStartTime = currentTimeMillis;
831        mElapsedRealtime = 0L;
832    }
833
834    private long currentTimeMillis() {
835        return mStartTime + mElapsedRealtime;
836    }
837
838    private void incrementCurrentTime(long duration) {
839        mElapsedRealtime += duration;
840    }
841
842    /**
843     * Creates a mock and registers it to {@link LocalServices}.
844     */
845    private static <T> T addLocalServiceMock(Class<T> clazz) {
846        final T mock = mock(clazz);
847        LocalServices.addService(clazz, mock);
848        return mock;
849    }
850
851    /**
852     * Custom Mockito answer used to verify async {@link INetworkPolicyListener} calls.
853     *
854     * <p>Typical usage:
855     * <pre><code>
856     *    mPolicyListener.expect().someCallback(any());
857     *    // do something on objects under test
858     *    mPolicyListener.waitAndVerify().someCallback(eq(expectedValue));
859     * </code></pre>
860     */
861    final class NetworkPolicyListenerAnswer implements Answer<Void> {
862        private CountDownLatch latch;
863        private final INetworkPolicyListener listener;
864
865        NetworkPolicyListenerAnswer(NetworkPolicyManagerService service) {
866            this.listener = mock(INetworkPolicyListener.class);
867            // RemoteCallbackList needs a binder to use as key
868            when(listener.asBinder()).thenReturn(new Binder());
869            service.registerListener(listener);
870        }
871
872        @Override
873        public Void answer(InvocationOnMock invocation) throws Throwable {
874            Log.d(TAG,"counting down on answer: " + invocation);
875            latch.countDown();
876            return null;
877        }
878
879        INetworkPolicyListener expect() {
880            assertNull("expect() called before waitAndVerify()", latch);
881            latch = new CountDownLatch(1);
882            return doAnswer(this).when(listener);
883        }
884
885        INetworkPolicyListener waitAndVerify() {
886            assertNotNull("waitAndVerify() called before expect()", latch);
887            try {
888                assertTrue("callback not called in 5 seconds", latch.await(5, TimeUnit.SECONDS));
889            } catch (InterruptedException e) {
890                fail("Thread interrupted before callback called");
891            } finally {
892                latch = null;
893            }
894            return verify(listener, atLeastOnce());
895        }
896    }
897
898    private void setNetpolicyXml(Context context) throws Exception {
899        mPolicyDir = context.getFilesDir();
900        if (mPolicyDir.exists()) {
901            IoUtils.deleteContents(mPolicyDir);
902        }
903        if (!TextUtils.isEmpty(mNetpolicyXml)) {
904            final String assetPath = NETPOLICY_DIR + "/" + mNetpolicyXml;
905            final File netConfigFile = new File(mPolicyDir, "netpolicy.xml");
906            Log.d(TAG, "Creating " + netConfigFile + " from asset " + assetPath);
907            try (final InputStream in = context.getResources().getAssets().open(assetPath);
908                    final OutputStream out = new FileOutputStream(netConfigFile)) {
909                Streams.copy(in, out);
910            }
911        }
912    }
913
914    /**
915     * Annotation used to define the relative path of the {@code netpolicy.xml} file.
916     */
917    @Retention(RetentionPolicy.RUNTIME)
918    @Target(ElementType.METHOD)
919    public @interface NetPolicyXml {
920
921        public String value() default "";
922
923    }
924
925    /**
926     * Rule used to set {@code mNetPolicyXml} according to the {@link NetPolicyXml} annotation.
927     */
928    public static class NetPolicyMethodRule implements MethodRule {
929
930        @Override
931        public Statement apply(Statement base, FrameworkMethod method, Object target) {
932            for (Annotation annotation : method.getAnnotations()) {
933                if ((annotation instanceof NetPolicyXml)) {
934                    final String path = ((NetPolicyXml) annotation).value();
935                    if (!path.isEmpty()) {
936                        ((NetworkPolicyManagerServiceTest) target).mNetpolicyXml = path;
937                        break;
938                    }
939                }
940            }
941            return base;
942        }
943    }
944}
945