NetworkPolicyManagerServiceTest.java revision 4414cea13908b8230640f84ef39603d68ff9c377
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import static android.content.Intent.ACTION_UID_REMOVED;
20import static android.content.Intent.EXTRA_UID;
21import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
22import static android.net.ConnectivityManager.TYPE_WIFI;
23import static android.net.NetworkPolicyManager.POLICY_NONE;
24import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
25import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
26import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
27import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
28import static android.net.NetworkStats.TAG_NONE;
29import static android.net.NetworkStats.UID_ALL;
30import static android.net.NetworkTemplate.MATCH_WIFI;
31import static org.easymock.EasyMock.anyInt;
32import static org.easymock.EasyMock.aryEq;
33import static org.easymock.EasyMock.capture;
34import static org.easymock.EasyMock.createMock;
35import static org.easymock.EasyMock.eq;
36import static org.easymock.EasyMock.expect;
37import static org.easymock.EasyMock.expectLastCall;
38import static org.easymock.EasyMock.isA;
39
40import android.app.IActivityManager;
41import android.app.INotificationManager;
42import android.app.IProcessObserver;
43import android.content.Intent;
44import android.content.pm.PackageInfo;
45import android.content.pm.PackageManager;
46import android.content.pm.Signature;
47import android.net.ConnectivityManager;
48import android.net.IConnectivityManager;
49import android.net.INetworkPolicyListener;
50import android.net.INetworkStatsService;
51import android.net.LinkProperties;
52import android.net.NetworkInfo;
53import android.net.NetworkInfo.DetailedState;
54import android.net.NetworkPolicy;
55import android.net.NetworkState;
56import android.net.NetworkStats;
57import android.net.NetworkTemplate;
58import android.os.Binder;
59import android.os.IPowerManager;
60import android.test.AndroidTestCase;
61import android.test.mock.MockPackageManager;
62import android.test.suitebuilder.annotation.LargeTest;
63import android.test.suitebuilder.annotation.Suppress;
64import android.text.format.Time;
65import android.util.TrustedTime;
66
67import com.android.server.net.NetworkPolicyManagerService;
68import com.google.common.util.concurrent.AbstractFuture;
69
70import org.easymock.Capture;
71import org.easymock.EasyMock;
72import org.easymock.IAnswer;
73
74import java.io.File;
75import java.util.concurrent.ExecutionException;
76import java.util.concurrent.Future;
77import java.util.concurrent.TimeUnit;
78import java.util.concurrent.TimeoutException;
79
80/**
81 * Tests for {@link NetworkPolicyManagerService}.
82 */
83@LargeTest
84public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
85    private static final String TAG = "NetworkPolicyManagerServiceTest";
86
87    private static final long TEST_START = 1194220800000L;
88    private static final String TEST_IFACE = "test0";
89
90    private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null);
91
92    private BroadcastInterceptingContext mServiceContext;
93    private File mPolicyDir;
94
95    private IActivityManager mActivityManager;
96    private IPowerManager mPowerManager;
97    private INetworkStatsService mStatsService;
98    private INetworkPolicyListener mPolicyListener;
99    private TrustedTime mTime;
100    private IConnectivityManager mConnManager;
101    private INotificationManager mNotifManager;
102
103    private NetworkPolicyManagerService mService;
104    private IProcessObserver mProcessObserver;
105
106    private Binder mStubBinder = new Binder();
107
108    private static final int UID_A = android.os.Process.FIRST_APPLICATION_UID + 800;
109    private static final int UID_B = android.os.Process.FIRST_APPLICATION_UID + 801;
110
111    private static final int PID_1 = 400;
112    private static final int PID_2 = 401;
113    private static final int PID_3 = 402;
114
115    @Override
116    public void setUp() throws Exception {
117        super.setUp();
118
119        // intercept various broadcasts, and pretend that uids have packages
120        mServiceContext = new BroadcastInterceptingContext(getContext()) {
121            @Override
122            public PackageManager getPackageManager() {
123                return new MockPackageManager() {
124                    @Override
125                    public String[] getPackagesForUid(int uid) {
126                        return new String[] { "com.example" };
127                    }
128
129                    @Override
130                    public PackageInfo getPackageInfo(String packageName, int flags) {
131                        final PackageInfo info = new PackageInfo();
132                        final Signature signature;
133                        if ("android".equals(packageName)) {
134                            signature = new Signature("F00D");
135                        } else {
136                            signature = new Signature("DEAD");
137                        }
138                        info.signatures = new Signature[] { signature };
139                        return info;
140                    }
141                };
142            }
143        };
144
145        mPolicyDir = getContext().getFilesDir();
146        for (File file : mPolicyDir.listFiles()) {
147            file.delete();
148        }
149
150        mActivityManager = createMock(IActivityManager.class);
151        mPowerManager = createMock(IPowerManager.class);
152        mStatsService = createMock(INetworkStatsService.class);
153        mPolicyListener = createMock(INetworkPolicyListener.class);
154        mTime = createMock(TrustedTime.class);
155        mConnManager = createMock(IConnectivityManager.class);
156        mNotifManager = createMock(INotificationManager.class);
157
158        mService = new NetworkPolicyManagerService(
159                mServiceContext, mActivityManager, mPowerManager, mStatsService, mTime, mPolicyDir);
160        mService.bindConnectivityManager(mConnManager);
161        mService.bindNotificationManager(mNotifManager);
162
163        // RemoteCallbackList needs a binder to use as key
164        expect(mPolicyListener.asBinder()).andReturn(mStubBinder).atLeastOnce();
165        replay();
166        mService.registerListener(mPolicyListener);
167        verifyAndReset();
168
169        // catch the registered IProcessObserver during systemReady()
170        final Capture<IProcessObserver> processObserver = new Capture<IProcessObserver>();
171        mActivityManager.registerProcessObserver(capture(processObserver));
172        expectLastCall().atLeastOnce();
173
174        // expect to answer screen status during systemReady()
175        expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
176        expectTime(System.currentTimeMillis());
177
178        replay();
179        mService.systemReady();
180        verifyAndReset();
181
182        mProcessObserver = processObserver.getValue();
183
184    }
185
186    @Override
187    public void tearDown() throws Exception {
188        for (File file : mPolicyDir.listFiles()) {
189            file.delete();
190        }
191
192        mServiceContext = null;
193        mPolicyDir = null;
194
195        mActivityManager = null;
196        mPowerManager = null;
197        mStatsService = null;
198        mPolicyListener = null;
199        mTime = null;
200
201        mService = null;
202        mProcessObserver = null;
203
204        super.tearDown();
205    }
206
207    @Suppress
208    public void testPolicyChangeTriggersBroadcast() throws Exception {
209        mService.setUidPolicy(UID_A, POLICY_NONE);
210
211        // change background policy and expect broadcast
212        final Future<Intent> backgroundChanged = mServiceContext.nextBroadcastIntent(
213                ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
214
215        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
216
217        backgroundChanged.get();
218    }
219
220    public void testPidForegroundCombined() throws Exception {
221        // push all uid into background
222        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
223        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
224        mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, false);
225        assertFalse(mService.isUidForeground(UID_A));
226        assertFalse(mService.isUidForeground(UID_B));
227
228        // push one of the shared pids into foreground
229        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
230        assertTrue(mService.isUidForeground(UID_A));
231        assertFalse(mService.isUidForeground(UID_B));
232
233        // and swap another uid into foreground
234        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
235        mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, true);
236        assertFalse(mService.isUidForeground(UID_A));
237        assertTrue(mService.isUidForeground(UID_B));
238
239        // push both pid into foreground
240        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
241        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
242        assertTrue(mService.isUidForeground(UID_A));
243
244        // pull one out, should still be foreground
245        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
246        assertTrue(mService.isUidForeground(UID_A));
247
248        // pull final pid out, should now be background
249        mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
250        assertFalse(mService.isUidForeground(UID_A));
251    }
252
253    public void testScreenChangesRules() throws Exception {
254        Future<Void> future;
255
256        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
257        replay();
258        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
259        future.get();
260        verifyAndReset();
261
262        // push strict policy for foreground uid, verify ALLOW rule
263        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
264        replay();
265        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
266        future.get();
267        verifyAndReset();
268
269        // now turn screen off and verify REJECT rule
270        expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
271        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
272        replay();
273        mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_OFF));
274        future.get();
275        verifyAndReset();
276
277        // and turn screen back on, verify ALLOW rule restored
278        expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
279        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
280        replay();
281        mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON));
282        future.get();
283        verifyAndReset();
284    }
285
286    public void testPolicyNone() throws Exception {
287        Future<Void> future;
288
289        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
290        replay();
291        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
292        future.get();
293        verifyAndReset();
294
295        // POLICY_NONE should RULE_ALLOW in foreground
296        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
297        replay();
298        mService.setUidPolicy(UID_A, POLICY_NONE);
299        future.get();
300        verifyAndReset();
301
302        // POLICY_NONE should RULE_ALLOW in background
303        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
304        replay();
305        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
306        future.get();
307        verifyAndReset();
308    }
309
310    public void testPolicyReject() throws Exception {
311        Future<Void> future;
312
313        // POLICY_REJECT should RULE_ALLOW in background
314        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
315        replay();
316        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
317        future.get();
318        verifyAndReset();
319
320        // POLICY_REJECT should RULE_ALLOW in foreground
321        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
322        replay();
323        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
324        future.get();
325        verifyAndReset();
326
327        // POLICY_REJECT should RULE_REJECT in background
328        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
329        replay();
330        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
331        future.get();
332        verifyAndReset();
333    }
334
335    public void testPolicyRejectAddRemove() throws Exception {
336        Future<Void> future;
337
338        // POLICY_NONE should have RULE_ALLOW in background
339        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
340        replay();
341        mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
342        mService.setUidPolicy(UID_A, POLICY_NONE);
343        future.get();
344        verifyAndReset();
345
346        // adding POLICY_REJECT should cause RULE_REJECT
347        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
348        replay();
349        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
350        future.get();
351        verifyAndReset();
352
353        // removing POLICY_REJECT should return us to RULE_ALLOW
354        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
355        replay();
356        mService.setUidPolicy(UID_A, POLICY_NONE);
357        future.get();
358        verifyAndReset();
359    }
360
361    public void testLastCycleBoundaryThisMonth() throws Exception {
362        // assume cycle day of "5th", which should be in same month
363        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
364        final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
365
366        final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 5, 1024L, 1024L);
367        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
368        assertEquals(expectedCycle, actualCycle);
369    }
370
371    public void testLastCycleBoundaryLastMonth() throws Exception {
372        // assume cycle day of "20th", which should be in last month
373        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
374        final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
375
376        final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 20, 1024L, 1024L);
377        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
378        assertEquals(expectedCycle, actualCycle);
379    }
380
381    public void testLastCycleBoundaryThisMonthFebruary() throws Exception {
382        // assume cycle day of "30th" in february; should go to january
383        final long currentTime = parseTime("2007-02-14T00:00:00.000Z");
384        final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
385
386        final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 30, 1024L, 1024L);
387        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
388        assertEquals(expectedCycle, actualCycle);
389    }
390
391    public void testLastCycleBoundaryLastMonthFebruary() throws Exception {
392        // assume cycle day of "30th" in february, which should clamp
393        final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
394        final long expectedCycle = parseTime("2007-03-01T00:00:00.000Z");
395
396        final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 30, 1024L, 1024L);
397        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
398        assertEquals(expectedCycle, actualCycle);
399    }
400
401    public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
402        long elapsedRealtime = 0;
403        NetworkState[] state = null;
404        NetworkStats stats = null;
405        Future<Void> future;
406
407        final long TIME_FEB_15 = 1171497600000L;
408        final long TIME_MAR_10 = 1173484800000L;
409        final int CYCLE_DAY = 15;
410
411        // first, pretend that wifi network comes online. no policy active,
412        // which means we shouldn't push limit to interface.
413        state = new NetworkState[] { buildWifi() };
414        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
415        expectTime(TIME_MAR_10 + elapsedRealtime);
416        future = expectMeteredIfacesChanged();
417
418        replay();
419        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
420        future.get();
421        verifyAndReset();
422
423        // now change cycle to be on 15th, and test in early march, to verify we
424        // pick cycle day in previous month.
425        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
426        expectTime(TIME_MAR_10 + elapsedRealtime);
427
428        // pretend that 512 bytes total have happened
429        stats = new NetworkStats(elapsedRealtime, 1)
430                .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 256L, 256L);
431        expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
432                .andReturn(stats).atLeastOnce();
433
434        // expect that quota remaining should be 1536 bytes
435        // TODO: write up NetworkManagementService mock
436
437        expectClearNotifications();
438        future = expectMeteredIfacesChanged(TEST_IFACE);
439
440        replay();
441        setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1024L, 2048L));
442        future.get();
443        verifyAndReset();
444    }
445
446    public void testUidRemovedPolicyCleared() throws Exception {
447        Future<Void> future;
448
449        // POLICY_REJECT should RULE_REJECT in background
450        future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
451        replay();
452        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
453        future.get();
454        verifyAndReset();
455
456        // uninstall should clear RULE_REJECT
457        future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
458        replay();
459        final Intent intent = new Intent(ACTION_UID_REMOVED);
460        intent.putExtra(EXTRA_UID, UID_A);
461        mServiceContext.sendBroadcast(intent);
462        future.get();
463        verifyAndReset();
464    }
465
466    private static long parseTime(String time) {
467        final Time result = new Time();
468        result.parse3339(time);
469        return result.toMillis(true);
470    }
471
472    private void setNetworkPolicies(NetworkPolicy... policies) {
473        mService.setNetworkPolicies(policies);
474    }
475
476    private static NetworkState buildWifi() {
477        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
478        info.setDetailedState(DetailedState.CONNECTED, null, null);
479        final LinkProperties prop = new LinkProperties();
480        prop.setInterfaceName(TEST_IFACE);
481        return new NetworkState(info, prop, null);
482    }
483
484    private void expectTime(long currentTime) throws Exception {
485        expect(mTime.forceRefresh()).andReturn(false).anyTimes();
486        expect(mTime.hasCache()).andReturn(true).anyTimes();
487        expect(mTime.currentTimeMillis()).andReturn(currentTime).anyTimes();
488        expect(mTime.getCacheAge()).andReturn(0L).anyTimes();
489        expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
490    }
491
492    private void expectClearNotifications() throws Exception {
493        mNotifManager.cancelNotificationWithTag(isA(String.class), isA(String.class), anyInt());
494        expectLastCall().anyTimes();
495    }
496
497    private Future<Void> expectRulesChanged(int uid, int policy) throws Exception {
498        final FutureAnswer future = new FutureAnswer();
499        mPolicyListener.onUidRulesChanged(eq(uid), eq(policy));
500        expectLastCall().andAnswer(future);
501        return future;
502    }
503
504    private Future<Void> expectMeteredIfacesChanged(String... ifaces) throws Exception {
505        final FutureAnswer future = new FutureAnswer();
506        mPolicyListener.onMeteredIfacesChanged(aryEq(ifaces));
507        expectLastCall().andAnswer(future);
508        return future;
509    }
510
511    private static class FutureAnswer extends AbstractFuture<Void> implements IAnswer<Void> {
512        @Override
513        public Void get() throws InterruptedException, ExecutionException {
514            try {
515                return get(5, TimeUnit.SECONDS);
516            } catch (TimeoutException e) {
517                throw new RuntimeException(e);
518            }
519        }
520
521        @Override
522        public Void answer() {
523            set(null);
524            return null;
525        }
526    }
527
528    private void replay() {
529        EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
530                mConnManager, mNotifManager);
531    }
532
533    private void verifyAndReset() {
534        EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
535                mConnManager, mNotifManager);
536        EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
537                mConnManager, mNotifManager);
538    }
539}
540