• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.cts.net.hostside;
18 
19 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
20 import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
21 
22 import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness;
23 import static com.android.cts.net.hostside.NetworkPolicyTestUtils.getActiveNetworkCapabilities;
24 import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
25 import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
26 import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
27 
28 import static org.junit.Assert.assertEquals;
29 import static org.junit.Assert.fail;
30 import static org.junit.Assume.assumeTrue;
31 
32 import android.net.Network;
33 import android.net.NetworkCapabilities;
34 import android.net.NetworkRequest;
35 import android.util.Log;
36 
37 import org.junit.After;
38 import org.junit.Before;
39 import org.junit.Rule;
40 import org.junit.Test;
41 
42 import java.util.Objects;
43 import java.util.concurrent.LinkedBlockingQueue;
44 import java.util.concurrent.TimeUnit;
45 
46 public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase {
47     private Network mNetwork;
48     private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback();
49     @Rule
50     public final MeterednessConfigurationRule mMeterednessConfiguration
51             = new MeterednessConfigurationRule();
52 
53     enum CallbackState {
54         NONE,
55         AVAILABLE,
56         LOST,
57         BLOCKED_STATUS,
58         CAPABILITIES
59     }
60 
61     private static class CallbackInfo {
62         public final CallbackState state;
63         public final Network network;
64         public final Object arg;
65 
CallbackInfo(CallbackState s, Network n, Object o)66         CallbackInfo(CallbackState s, Network n, Object o) {
67             state = s; network = n; arg = o;
68         }
69 
toString()70         public String toString() {
71             return String.format("%s (%s) (%s)", state, network, arg);
72         }
73 
74         @Override
equals(Object o)75         public boolean equals(Object o) {
76             if (!(o instanceof CallbackInfo)) return false;
77             // Ignore timeMs, since it's unpredictable.
78             final CallbackInfo other = (CallbackInfo) o;
79             return (state == other.state) && Objects.equals(network, other.network)
80                     && Objects.equals(arg, other.arg);
81         }
82 
83         @Override
hashCode()84         public int hashCode() {
85             return Objects.hash(state, network, arg);
86         }
87     }
88 
89     private class TestNetworkCallback extends INetworkCallback.Stub {
90         private static final int TEST_CONNECT_TIMEOUT_MS = 30_000;
91         private static final int TEST_CALLBACK_TIMEOUT_MS = 5_000;
92 
93         private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
94 
setLastCallback(CallbackState state, Network network, Object o)95         protected void setLastCallback(CallbackState state, Network network, Object o) {
96             mCallbacks.offer(new CallbackInfo(state, network, o));
97         }
98 
nextCallback(int timeoutMs)99         CallbackInfo nextCallback(int timeoutMs) {
100             CallbackInfo cb = null;
101             try {
102                 cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
103             } catch (InterruptedException e) {
104             }
105             if (cb == null) {
106                 fail("Did not receive callback after " + timeoutMs + "ms");
107             }
108             return cb;
109         }
110 
expectCallback(CallbackState state, Network expectedNetwork, Object o)111         CallbackInfo expectCallback(CallbackState state, Network expectedNetwork, Object o) {
112             final CallbackInfo expected = new CallbackInfo(state, expectedNetwork, o);
113             final CallbackInfo actual = nextCallback(TEST_CALLBACK_TIMEOUT_MS);
114             assertEquals("Unexpected callback:", expected, actual);
115             return actual;
116         }
117 
118         @Override
onAvailable(Network network)119         public void onAvailable(Network network) {
120             setLastCallback(CallbackState.AVAILABLE, network, null);
121         }
122 
123         @Override
onLost(Network network)124         public void onLost(Network network) {
125             setLastCallback(CallbackState.LOST, network, null);
126         }
127 
128         @Override
onBlockedStatusChanged(Network network, boolean blocked)129         public void onBlockedStatusChanged(Network network, boolean blocked) {
130             setLastCallback(CallbackState.BLOCKED_STATUS, network, blocked);
131         }
132 
133         @Override
onCapabilitiesChanged(Network network, NetworkCapabilities cap)134         public void onCapabilitiesChanged(Network network, NetworkCapabilities cap) {
135             setLastCallback(CallbackState.CAPABILITIES, network, cap);
136         }
137 
expectAvailableCallbackAndGetNetwork()138         public Network expectAvailableCallbackAndGetNetwork() {
139             final CallbackInfo cb = nextCallback(TEST_CONNECT_TIMEOUT_MS);
140             if (cb.state != CallbackState.AVAILABLE) {
141                 fail("Network is not available. Instead obtained the following callback :"
142                         + cb);
143             }
144             return cb.network;
145         }
146 
expectBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked)147         public void expectBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked) {
148             expectCallback(CallbackState.BLOCKED_STATUS, expectedNetwork, expectBlocked);
149         }
150 
expectBlockedStatusCallbackEventually(Network expectedNetwork, boolean expectBlocked)151         public void expectBlockedStatusCallbackEventually(Network expectedNetwork,
152                 boolean expectBlocked) {
153             final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS;
154             do {
155                 final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis()));
156                 if (cb.state == CallbackState.BLOCKED_STATUS
157                         && cb.network.equals(expectedNetwork)) {
158                     assertEquals(expectBlocked, cb.arg);
159                     return;
160                 }
161             } while (System.currentTimeMillis() <= deadline);
162             fail("Didn't receive onBlockedStatusChanged()");
163         }
164 
expectCapabilitiesCallbackEventually(Network expectedNetwork, boolean hasCap, int cap)165         public void expectCapabilitiesCallbackEventually(Network expectedNetwork, boolean hasCap,
166                 int cap) {
167             final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS;
168             do {
169                 final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis()));
170                 if (cb.state != CallbackState.CAPABILITIES
171                         || !expectedNetwork.equals(cb.network)
172                         || (hasCap != ((NetworkCapabilities) cb.arg).hasCapability(cap))) {
173                     Log.i("NetworkCallbackTest#expectCapabilitiesCallback",
174                             "Ignoring non-matching callback : " + cb);
175                     continue;
176                 }
177                 // Found a match, return
178                 return;
179             } while (System.currentTimeMillis() <= deadline);
180             fail("Didn't receive the expected callback to onCapabilitiesChanged(). Check the "
181                     + "log for a list of received callbacks, if any.");
182         }
183     }
184 
185     @Before
setUp()186     public void setUp() throws Exception {
187         super.setUp();
188 
189         assumeTrue(canChangeActiveNetworkMeteredness());
190 
191         registerBroadcastReceiver();
192 
193         removeRestrictBackgroundWhitelist(mUid);
194         removeRestrictBackgroundBlacklist(mUid);
195         assertRestrictBackgroundChangedReceived(0);
196 
197         // Initial state
198         setBatterySaverMode(false);
199         setRestrictBackground(false);
200 
201         // Get transports of the active network, this has to be done before changing meteredness,
202         // since wifi will be disconnected when changing from non-metered to metered.
203         final NetworkCapabilities networkCapabilities = getActiveNetworkCapabilities();
204 
205         // Mark network as metered.
206         mMeterednessConfiguration.configureNetworkMeteredness(true);
207 
208         // Register callback, copy the capabilities from the active network to expect the "original"
209         // network before disconnecting, but null out some fields to prevent over-specified.
210         registerNetworkCallback(new NetworkRequest.Builder()
211                 .setCapabilities(networkCapabilities.setTransportInfo(null))
212                 .removeCapability(NET_CAPABILITY_NOT_METERED)
213                 .setSignalStrength(SIGNAL_STRENGTH_UNSPECIFIED).build(), mTestNetworkCallback);
214         // Wait for onAvailable() callback to ensure network is available before the test
215         // and store the default network.
216         mNetwork = mTestNetworkCallback.expectAvailableCallbackAndGetNetwork();
217         // Check that the network is metered.
218         mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
219                 false /* hasCapability */, NET_CAPABILITY_NOT_METERED);
220         mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false);
221     }
222 
223     @After
tearDown()224     public void tearDown() throws Exception {
225         super.tearDown();
226 
227         setRestrictBackground(false);
228         setBatterySaverMode(false);
229         unregisterNetworkCallback();
230     }
231 
232     @RequiredProperties({DATA_SAVER_MODE})
233     @Test
testOnBlockedStatusChanged_dataSaver()234     public void testOnBlockedStatusChanged_dataSaver() throws Exception {
235         try {
236             // Enable restrict background
237             setRestrictBackground(true);
238             assertBackgroundNetworkAccess(false);
239             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
240 
241             // Add to whitelist
242             addRestrictBackgroundWhitelist(mUid);
243             assertBackgroundNetworkAccess(true);
244             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
245 
246             // Remove from whitelist
247             removeRestrictBackgroundWhitelist(mUid);
248             assertBackgroundNetworkAccess(false);
249             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
250         } finally {
251             mMeterednessConfiguration.resetNetworkMeteredness();
252         }
253 
254         // Set to non-metered network
255         mMeterednessConfiguration.configureNetworkMeteredness(false);
256         mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
257                 true /* hasCapability */, NET_CAPABILITY_NOT_METERED);
258         try {
259             assertBackgroundNetworkAccess(true);
260             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
261 
262             // Disable restrict background, should not trigger callback
263             setRestrictBackground(false);
264             assertBackgroundNetworkAccess(true);
265         } finally {
266             mMeterednessConfiguration.resetNetworkMeteredness();
267         }
268     }
269 
270     @RequiredProperties({BATTERY_SAVER_MODE})
271     @Test
testOnBlockedStatusChanged_powerSaver()272     public void testOnBlockedStatusChanged_powerSaver() throws Exception {
273         try {
274             // Enable Power Saver
275             setBatterySaverMode(true);
276             assertBackgroundNetworkAccess(false);
277             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
278 
279             // Disable Power Saver
280             setBatterySaverMode(false);
281             assertBackgroundNetworkAccess(true);
282             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
283         } finally {
284             mMeterednessConfiguration.resetNetworkMeteredness();
285         }
286 
287         // Set to non-metered network
288         mMeterednessConfiguration.configureNetworkMeteredness(false);
289         mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
290                 true /* hasCapability */, NET_CAPABILITY_NOT_METERED);
291         try {
292             // Enable Power Saver
293             setBatterySaverMode(true);
294             assertBackgroundNetworkAccess(false);
295             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
296 
297             // Disable Power Saver
298             setBatterySaverMode(false);
299             assertBackgroundNetworkAccess(true);
300             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
301         } finally {
302             mMeterednessConfiguration.resetNetworkMeteredness();
303         }
304     }
305 
306     // TODO: 1. test against VPN lockdown.
307     //       2. test against multiple networks.
308 }
309