1 /*
2  * Copyright (C) 2012 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 
17 package com.android.server;
18 
19 import static android.util.DebugUtils.valueToString;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertTrue;
24 import static org.mockito.ArgumentMatchers.anyBoolean;
25 import static org.mockito.Mockito.doNothing;
26 import static org.mockito.Mockito.doReturn;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.reset;
29 import static org.mockito.Mockito.timeout;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.verifyNoMoreInteractions;
32 
33 import android.annotation.NonNull;
34 import android.content.Context;
35 import android.net.INetd;
36 import android.net.INetdUnsolicitedEventListener;
37 import android.net.LinkAddress;
38 import android.net.NetworkPolicyManager;
39 import android.os.BatteryStats;
40 import android.os.Binder;
41 import android.os.Build;
42 import android.os.IBinder;
43 import android.os.Process;
44 import android.os.RemoteException;
45 import android.test.suitebuilder.annotation.SmallTest;
46 import android.util.ArrayMap;
47 
48 import com.android.internal.app.IBatteryStats;
49 import com.android.server.NetworkManagementService.Dependencies;
50 import com.android.server.net.BaseNetworkObserver;
51 import com.android.testutils.DevSdkIgnoreRule;
52 import com.android.testutils.DevSdkIgnoreRunner;
53 
54 import org.junit.After;
55 import org.junit.Before;
56 import org.junit.Test;
57 import org.junit.runner.RunWith;
58 import org.mockito.ArgumentCaptor;
59 import org.mockito.Captor;
60 import org.mockito.Mock;
61 import org.mockito.MockitoAnnotations;
62 
63 import java.util.function.BiFunction;
64 
65 /**
66  * Tests for {@link NetworkManagementService}.
67  */
68 @RunWith(DevSdkIgnoreRunner.class)
69 @SmallTest
70 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
71 public class NetworkManagementServiceTest {
72     private NetworkManagementService mNMService;
73     @Mock private Context mContext;
74     @Mock private IBatteryStats.Stub mBatteryStatsService;
75     @Mock private INetd.Stub mNetdService;
76 
77     private static final int TEST_UID = 111;
78 
79     @NonNull
80     @Captor
81     private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
82 
83     private final MockDependencies mDeps = new MockDependencies();
84 
85     private final class MockDependencies extends Dependencies {
86         @Override
87         public IBinder getService(String name) {
88             switch (name) {
89                 case BatteryStats.SERVICE_NAME:
90                     return mBatteryStatsService;
91                 default:
92                     throw new UnsupportedOperationException("Unknown service " + name);
93             }
94         }
95 
96         @Override
97         public void registerLocalService(NetworkManagementInternal nmi) {
98         }
99 
100         @Override
101         public INetd getNetd() {
102             return mNetdService;
103         }
104 
105         @Override
106         public int getCallingUid() {
107             return Process.SYSTEM_UID;
108         }
109     }
110 
111     @Before
112     public void setUp() throws Exception {
113         MockitoAnnotations.initMocks(this);
114         doNothing().when(mNetdService)
115                 .registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
116         // Start the service and wait until it connects to our socket.
117         mNMService = NetworkManagementService.create(mContext, mDeps);
118     }
119 
120     @After
121     public void tearDown() throws Exception {
122         mNMService.shutdown();
123     }
124 
125     private static <T> T expectSoon(T mock) {
126         return verify(mock, timeout(200));
127     }
128 
129     /**
130      * Tests that network observers work properly.
131      */
132     @Test
133     public void testNetworkObservers() throws Exception {
134         BaseNetworkObserver observer = mock(BaseNetworkObserver.class);
135         doReturn(new Binder()).when(observer).asBinder();  // Used by registerObserver.
136         mNMService.registerObserver(observer);
137 
138         // Forget everything that happened to the mock so far, so we can explicitly verify
139         // everything that happens and does not happen to it from now on.
140 
141         INetdUnsolicitedEventListener unsolListener = mUnsolListenerCaptor.getValue();
142         reset(observer);
143         // Now call unsolListener methods and ensure that the observer methods are
144         // called. After every method we expect a callback soon after; to ensure that
145         // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
146 
147         /**
148          * Interface changes.
149          */
150         unsolListener.onInterfaceAdded("rmnet12");
151         expectSoon(observer).interfaceAdded("rmnet12");
152 
153         unsolListener.onInterfaceRemoved("eth1");
154         expectSoon(observer).interfaceRemoved("eth1");
155 
156         unsolListener.onInterfaceChanged("clat4", true);
157         expectSoon(observer).interfaceStatusChanged("clat4", true);
158 
159         unsolListener.onInterfaceLinkStateChanged("rmnet0", false);
160         expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
161 
162         /**
163          * Bandwidth control events.
164          */
165         unsolListener.onQuotaLimitReached("data", "rmnet_usb0");
166         expectSoon(observer).limitReached("data", "rmnet_usb0");
167 
168         /**
169          * Interface class activity.
170          */
171         unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, TEST_UID);
172         expectSoon(observer).interfaceClassDataActivityChanged(1, true, 1234, TEST_UID);
173 
174         unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, TEST_UID);
175         expectSoon(observer).interfaceClassDataActivityChanged(9, false, 5678, TEST_UID);
176 
177         unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, TEST_UID);
178         expectSoon(observer).interfaceClassDataActivityChanged(9, false, 4321, TEST_UID);
179 
180         /**
181          * IP address changes.
182          */
183         unsolListener.onInterfaceAddressUpdated("fe80::1/64", "wlan0", 128, 253);
184         expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253));
185 
186         unsolListener.onInterfaceAddressRemoved("fe80::1/64", "wlan0", 128, 253);
187         expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253));
188 
189         unsolListener.onInterfaceAddressRemoved("2001:db8::1/64", "wlan0", 1, 0);
190         expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0));
191 
192         /**
193          * DNS information broadcasts.
194          */
195         unsolListener.onInterfaceDnsServerInfo("rmnet_usb0", 3600, new String[]{"2001:db8::1"});
196         expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600,
197                 new String[]{"2001:db8::1"});
198 
199         unsolListener.onInterfaceDnsServerInfo("wlan0", 14400,
200                 new String[]{"2001:db8::1", "2001:db8::2"});
201         expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400,
202                 new String[]{"2001:db8::1", "2001:db8::2"});
203 
204         // We don't check for negative lifetimes, only for parse errors.
205         unsolListener.onInterfaceDnsServerInfo("wlan0", -3600, new String[]{"::1"});
206         expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600,
207                 new String[]{"::1"});
208 
209         // No syntax checking on the addresses.
210         unsolListener.onInterfaceDnsServerInfo("wlan0", 600,
211                 new String[]{"", "::", "", "foo", "::1"});
212         expectSoon(observer).interfaceDnsServerInfo("wlan0", 600,
213                 new String[]{"", "::", "", "foo", "::1"});
214 
215         // Make sure nothing else was called.
216         verifyNoMoreInteractions(observer);
217     }
218 
219     @Test
220     public void testFirewallEnabled() {
221         mNMService.setFirewallEnabled(true);
222         assertTrue(mNMService.isFirewallEnabled());
223 
224         mNMService.setFirewallEnabled(false);
225         assertFalse(mNMService.isFirewallEnabled());
226     }
227 
228     @Test
229     public void testNetworkRestrictedDefault() {
230         assertFalse(mNMService.isNetworkRestricted(TEST_UID));
231     }
232 
233     @Test
234     public void testMeteredNetworkRestrictions() throws RemoteException {
235         // Make sure the mocked netd method returns true.
236         doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
237 
238         // Restrict usage of mobile data in background
239         mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, true);
240         assertTrue("Should be true since mobile data usage is restricted",
241                 mNMService.isNetworkRestricted(TEST_UID));
242 
243         mNMService.setDataSaverModeEnabled(true);
244         verify(mNetdService).bandwidthEnableDataSaver(true);
245 
246         mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, false);
247         assertTrue("Should be true since data saver is on and the uid is not allowlisted",
248                 mNMService.isNetworkRestricted(TEST_UID));
249 
250         mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, true);
251         assertFalse("Should be false since data saver is on and the uid is allowlisted",
252                 mNMService.isNetworkRestricted(TEST_UID));
253 
254         // remove uid from allowlist and turn datasaver off again
255         mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, false);
256         mNMService.setDataSaverModeEnabled(false);
257         verify(mNetdService).bandwidthEnableDataSaver(false);
258         assertFalse("Network should not be restricted when data saver is off",
259                 mNMService.isNetworkRestricted(TEST_UID));
260     }
261 
262     @Test
263     public void testFirewallChains() {
264         final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
265         // Dozable chain
266         final ArrayMap<Integer, Boolean> isRestrictedForDozable = new ArrayMap<>();
267         isRestrictedForDozable.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
268         isRestrictedForDozable.put(INetd.FIREWALL_RULE_ALLOW, false);
269         isRestrictedForDozable.put(INetd.FIREWALL_RULE_DENY, true);
270         expected.put(INetd.FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
271         // Powersaver chain
272         final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
273         isRestrictedForPowerSave.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
274         isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_ALLOW, false);
275         isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_DENY, true);
276         expected.put(INetd.FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
277         // Standby chain
278         final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
279         isRestrictedForStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, false);
280         isRestrictedForStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
281         isRestrictedForStandby.put(INetd.FIREWALL_RULE_DENY, true);
282         expected.put(INetd.FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
283         // Restricted mode chain
284         final ArrayMap<Integer, Boolean> isRestrictedForRestrictedMode = new ArrayMap<>();
285         isRestrictedForRestrictedMode.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
286         isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_ALLOW, false);
287         isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_DENY, true);
288         expected.put(INetd.FIREWALL_CHAIN_RESTRICTED, isRestrictedForRestrictedMode);
289 
290         final int[] chains = {
291                 INetd.FIREWALL_CHAIN_STANDBY,
292                 INetd.FIREWALL_CHAIN_POWERSAVE,
293                 INetd.FIREWALL_CHAIN_DOZABLE,
294                 INetd.FIREWALL_CHAIN_RESTRICTED
295         };
296         final int[] states = {
297                 INetd.FIREWALL_RULE_ALLOW,
298                 INetd.FIREWALL_RULE_DENY,
299                 NetworkPolicyManager.FIREWALL_RULE_DEFAULT
300         };
301         BiFunction<Integer, Integer, String> errorMsg = (chain, state) -> {
302             return String.format("Unexpected value for chain: %s and state: %s",
303                     valueToString(INetd.class, "FIREWALL_CHAIN_", chain),
304                     valueToString(INetd.class, "FIREWALL_RULE_", state));
305         };
306         for (int chain : chains) {
307             final ArrayMap<Integer, Boolean> expectedValues = expected.get(chain);
308             mNMService.setFirewallChainEnabled(chain, true);
309             for (int state : states) {
310                 mNMService.setFirewallUidRule(chain, TEST_UID, state);
311                 assertEquals(errorMsg.apply(chain, state),
312                         expectedValues.get(state), mNMService.isNetworkRestricted(TEST_UID));
313             }
314             mNMService.setFirewallChainEnabled(chain, false);
315         }
316     }
317 }
318