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