• 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.netpolicy.hostside;
18 
19 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
20 import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
21 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
22 
23 import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness;
24 import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.getActiveNetworkCapabilities;
25 import static com.android.cts.netpolicy.hostside.NetworkPolicyTestUtils.setRestrictBackground;
26 import static com.android.cts.netpolicy.hostside.Property.BATTERY_SAVER_MODE;
27 import static com.android.cts.netpolicy.hostside.Property.DATA_SAVER_MODE;
28 
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.fail;
31 import static org.junit.Assume.assumeTrue;
32 
33 import android.net.Network;
34 import android.net.NetworkCapabilities;
35 import android.net.NetworkRequest;
36 import android.net.cts.util.CtsNetUtils;
37 import android.os.SystemClock;
38 import android.util.Log;
39 
40 import com.android.modules.utils.build.SdkLevel;
41 
42 import org.junit.After;
43 import org.junit.Before;
44 import org.junit.Rule;
45 import org.junit.Test;
46 
47 import java.util.ArrayList;
48 import java.util.Objects;
49 import java.util.concurrent.LinkedBlockingQueue;
50 import java.util.concurrent.TimeUnit;
51 
52 public class NetworkCallbackTest extends AbstractRestrictBackgroundNetworkTestCase {
53     private Network mNetwork;
54     private final TestNetworkCallback mTestNetworkCallback = new TestNetworkCallback();
55     private CtsNetUtils mCtsNetUtils;
56     private static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google";
57 
58     @Rule
59     public final MeterednessConfigurationRule mMeterednessConfiguration
60             = new MeterednessConfigurationRule();
61 
62     enum CallbackState {
63         NONE,
64         AVAILABLE,
65         LOST,
66         BLOCKED_STATUS,
67         CAPABILITIES
68     }
69 
70     private static class CallbackInfo {
71         public final CallbackState state;
72         public final Network network;
73         public final Object arg;
74 
CallbackInfo(CallbackState s, Network n, Object o)75         CallbackInfo(CallbackState s, Network n, Object o) {
76             state = s; network = n; arg = o;
77         }
78 
toString()79         public String toString() {
80             return String.format("%s (%s) (%s)", state, network, arg);
81         }
82 
83         @Override
equals(Object o)84         public boolean equals(Object o) {
85             if (!(o instanceof CallbackInfo)) return false;
86             // Ignore timeMs, since it's unpredictable.
87             final CallbackInfo other = (CallbackInfo) o;
88             return (state == other.state) && Objects.equals(network, other.network)
89                     && Objects.equals(arg, other.arg);
90         }
91 
92         @Override
hashCode()93         public int hashCode() {
94             return Objects.hash(state, network, arg);
95         }
96     }
97 
98     private class TestNetworkCallback extends INetworkCallback.Stub {
99         private static final int TEST_CONNECT_TIMEOUT_MS = 30_000;
100         private static final int TEST_CALLBACK_TIMEOUT_MS = 5_000;
101 
102         private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
103 
setLastCallback(CallbackState state, Network network, Object o)104         protected void setLastCallback(CallbackState state, Network network, Object o) {
105             mCallbacks.offer(new CallbackInfo(state, network, o));
106         }
107 
nextCallback(int timeoutMs)108         CallbackInfo nextCallback(int timeoutMs) {
109             CallbackInfo cb = null;
110             try {
111                 cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
112             } catch (InterruptedException e) {
113             }
114             if (cb == null) {
115                 fail("Did not receive callback after " + timeoutMs + "ms");
116             }
117             return cb;
118         }
119 
expectCallback(CallbackState state, Network expectedNetwork, Object o)120         CallbackInfo expectCallback(CallbackState state, Network expectedNetwork, Object o) {
121             final CallbackInfo expected = new CallbackInfo(state, expectedNetwork, o);
122             final CallbackInfo actual = nextCallback(TEST_CALLBACK_TIMEOUT_MS);
123             assertEquals("Unexpected callback:", expected, actual);
124             return actual;
125         }
126 
127         @Override
onAvailable(Network network)128         public void onAvailable(Network network) {
129             setLastCallback(CallbackState.AVAILABLE, network, null);
130         }
131 
132         @Override
onLost(Network network)133         public void onLost(Network network) {
134             setLastCallback(CallbackState.LOST, network, null);
135         }
136 
137         @Override
onBlockedStatusChanged(Network network, boolean blocked)138         public void onBlockedStatusChanged(Network network, boolean blocked) {
139             setLastCallback(CallbackState.BLOCKED_STATUS, network, blocked);
140         }
141 
142         @Override
onCapabilitiesChanged(Network network, NetworkCapabilities cap)143         public void onCapabilitiesChanged(Network network, NetworkCapabilities cap) {
144             setLastCallback(CallbackState.CAPABILITIES, network, cap);
145         }
146 
expectAvailableCallbackAndGetNetwork()147         public Network expectAvailableCallbackAndGetNetwork() {
148             final CallbackInfo cb = nextCallback(TEST_CONNECT_TIMEOUT_MS);
149             if (cb.state != CallbackState.AVAILABLE) {
150                 fail("Network is not available. Instead obtained the following callback :" + cb);
151             }
152             return cb.network;
153         }
154 
drainAndWaitForIdle()155         public void drainAndWaitForIdle() {
156             try {
157                 do {
158                     mCallbacks.drainTo(new ArrayList<>());
159                 } while (mCallbacks.poll(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS) != null);
160             } catch (InterruptedException ie) {
161                 Log.e(TAG, "Interrupted while draining callback queue", ie);
162                 Thread.currentThread().interrupt();
163             }
164         }
165 
expectBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked)166         public void expectBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked) {
167             expectCallback(CallbackState.BLOCKED_STATUS, expectedNetwork, expectBlocked);
168         }
169 
expectBlockedStatusCallbackEventually(Network expectedNetwork, boolean expectBlocked)170         public void expectBlockedStatusCallbackEventually(Network expectedNetwork,
171                 boolean expectBlocked) {
172             final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS;
173             do {
174                 final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis()));
175                 if (cb.state == CallbackState.BLOCKED_STATUS
176                         && cb.network.equals(expectedNetwork)) {
177                     assertEquals(expectBlocked, cb.arg);
178                     return;
179                 }
180             } while (System.currentTimeMillis() <= deadline);
181             fail("Didn't receive onBlockedStatusChanged()");
182         }
183 
expectCapabilitiesCallbackEventually(Network expectedNetwork, boolean hasCap, int cap)184         public void expectCapabilitiesCallbackEventually(Network expectedNetwork, boolean hasCap,
185                 int cap) {
186             final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS;
187             do {
188                 final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis()));
189                 if (cb.state != CallbackState.CAPABILITIES
190                         || !expectedNetwork.equals(cb.network)
191                         || (hasCap != ((NetworkCapabilities) cb.arg).hasCapability(cap))) {
192                     Log.i("NetworkCallbackTest#expectCapabilitiesCallback",
193                             "Ignoring non-matching callback : " + cb);
194                     continue;
195                 }
196                 // Found a match, return
197                 return;
198             } while (System.currentTimeMillis() <= deadline);
199             fail("Didn't receive the expected callback to onCapabilitiesChanged(). Check the "
200                     + "log for a list of received callbacks, if any.");
201         }
202     }
203 
204     @Before
setUp()205     public void setUp() throws Exception {
206         super.setUp();
207 
208         assumeTrue(canChangeActiveNetworkMeteredness());
209 
210         registerBroadcastReceiver();
211 
212         removeRestrictBackgroundWhitelist(mUid);
213         removeRestrictBackgroundBlacklist(mUid);
214         assertRestrictBackgroundChangedReceived(0);
215 
216         // Initial state
217         setBatterySaverMode(false);
218         setRestrictBackground(false);
219         setAppIdle(false);
220 
221         // Get transports of the active network, this has to be done before changing meteredness,
222         // since wifi will be disconnected when changing from non-metered to metered.
223         final NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder()
224                 .clearCapabilities();
225         final NetworkCapabilities networkCapabilities = getActiveNetworkCapabilities();
226         for (final int capability : networkCapabilities.getCapabilities()) {
227             networkRequestBuilder.addCapability(capability);
228         }
229         for (final int transportType : networkCapabilities.getTransportTypes()) {
230             networkRequestBuilder.addTransportType(transportType);
231         }
232         networkRequestBuilder.setNetworkSpecifier(networkCapabilities.getNetworkSpecifier());
233         networkRequestBuilder.removeCapability(NET_CAPABILITY_NOT_METERED);
234 
235         // Mark network as metered.
236         mMeterednessConfiguration.configureNetworkMeteredness(true);
237 
238         // Register callback, copy the capabilities from the active network to expect the "original"
239         // network before disconnecting, but null out some fields to prevent over-specified.
240         registerNetworkCallback(networkRequestBuilder.build(), mTestNetworkCallback);
241         // Wait for onAvailable() callback to ensure network is available before the test
242         // and store the default network.
243         mNetwork = mTestNetworkCallback.expectAvailableCallbackAndGetNetwork();
244         // Check that the network is metered.
245         mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
246                 false /* hasCapability */, NET_CAPABILITY_NOT_METERED);
247         mTestNetworkCallback.drainAndWaitForIdle();
248 
249         // Before Android T, DNS queries over private DNS should be but are not restricted by Power
250         // Saver or Data Saver. The issue is fixed in mainline update and apps can no longer request
251         // DNS queries when its network is restricted by Power Saver. The fix takes effect backwards
252         // starting from Android T. But for Data Saver, the fix is not backward compatible since
253         // there are some platform changes involved. It is only available on devices that a specific
254         // trunk flag is enabled.
255         //
256         // This test can not only verify that the network traffic from apps is blocked at the right
257         // time, but also verify whether it is correctly blocked at the DNS stage, or at a later
258         // socket connection stage.
259         if (SdkLevel.isAtLeastT()) {
260             // Enable private DNS
261             mCtsNetUtils = new CtsNetUtils(mContext);
262             mCtsNetUtils.storePrivateDnsSetting();
263             mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER);
264             mCtsNetUtils.awaitPrivateDnsSetting(
265                     "NetworkCallbackTest wait private DNS setting timeout", mNetwork,
266                     GOOGLE_PRIVATE_DNS_SERVER, true);
267         }
268     }
269 
270     @After
tearDown()271     public void tearDown() throws Exception {
272         super.tearDown();
273 
274         setRestrictBackground(false);
275         setBatterySaverMode(false);
276         unregisterNetworkCallback();
277         stopApp();
278 
279         if (SdkLevel.isAtLeastT() && (mCtsNetUtils != null)) {
280             mCtsNetUtils.restorePrivateDnsSetting();
281         }
282     }
283 
284     @RequiredProperties({DATA_SAVER_MODE})
285     @Test
testOnBlockedStatusChanged_dataSaver()286     public void testOnBlockedStatusChanged_dataSaver() throws Exception {
287         try {
288             // Enable restrict background
289             setRestrictBackground(true);
290             // TODO: Verify expectedUnavailableError when aconfig support mainline.
291             // (see go/aconfig-in-mainline-problems)
292             assertBackgroundNetworkAccess(false);
293             assertNetworkAccessBlockedByBpf(true, mUid, true /* metered */);
294             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
295 
296             // Add to whitelist
297             addRestrictBackgroundWhitelist(mUid);
298             assertBackgroundNetworkAccess(true);
299             assertNetworkAccessBlockedByBpf(false, mUid, true /* metered */);
300             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
301 
302             // Remove from whitelist
303             removeRestrictBackgroundWhitelist(mUid);
304             // TODO: Verify expectedUnavailableError when aconfig support mainline.
305             assertBackgroundNetworkAccess(false);
306             assertNetworkAccessBlockedByBpf(true, mUid, true /* metered */);
307             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
308         } finally {
309             mMeterednessConfiguration.resetNetworkMeteredness();
310         }
311 
312         // Set to non-metered network
313         mMeterednessConfiguration.configureNetworkMeteredness(false);
314         mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
315                 true /* hasCapability */, NET_CAPABILITY_NOT_METERED);
316         try {
317             assertBackgroundNetworkAccess(true);
318             assertNetworkAccessBlockedByBpf(false, mUid, false /* metered */);
319             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
320 
321             // Disable restrict background, should not trigger callback
322             setRestrictBackground(false);
323             assertBackgroundNetworkAccess(true);
324             assertNetworkAccessBlockedByBpf(false, mUid, false /* metered */);
325         } finally {
326             mMeterednessConfiguration.resetNetworkMeteredness();
327         }
328     }
329 
330     @RequiredProperties({BATTERY_SAVER_MODE})
331     @Test
testOnBlockedStatusChanged_powerSaver()332     public void testOnBlockedStatusChanged_powerSaver() throws Exception {
333         try {
334             // Enable Power Saver
335             setBatterySaverMode(true);
336             if (SdkLevel.isAtLeastT()) {
337                 assertProcessStateBelow(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
338                 assertNetworkAccess(false, "java.net.UnknownHostException");
339             } else {
340                 assertBackgroundNetworkAccess(false);
341             }
342             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
343             assertNetworkAccessBlockedByBpf(true, mUid, true /* metered */);
344 
345             // Disable Power Saver
346             setBatterySaverMode(false);
347             assertBackgroundNetworkAccess(true);
348             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
349             assertNetworkAccessBlockedByBpf(false, mUid, true /* metered */);
350         } finally {
351             mMeterednessConfiguration.resetNetworkMeteredness();
352         }
353 
354         // Set to non-metered network
355         mMeterednessConfiguration.configureNetworkMeteredness(false);
356         mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
357                 true /* hasCapability */, NET_CAPABILITY_NOT_METERED);
358         try {
359             // Enable Power Saver
360             setBatterySaverMode(true);
361             if (SdkLevel.isAtLeastT()) {
362                 assertProcessStateBelow(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
363                 assertNetworkAccess(false, "java.net.UnknownHostException");
364             } else {
365                 assertBackgroundNetworkAccess(false);
366             }
367             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
368             assertNetworkAccessBlockedByBpf(true, mUid, false /* metered */);
369 
370             // Disable Power Saver
371             setBatterySaverMode(false);
372             assertBackgroundNetworkAccess(true);
373             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
374             assertNetworkAccessBlockedByBpf(false, mUid, false /* metered */);
375         } finally {
376             mMeterednessConfiguration.resetNetworkMeteredness();
377         }
378     }
379 
380     @Test
testOnBlockedStatusChanged_default()381     public void testOnBlockedStatusChanged_default() throws Exception {
382         try {
383             assertProcessStateBelow(PROCESS_STATE_TOP_SLEEPING);
384             assertNetworkAccess(false, null);
385             assertNetworkAccessBlockedByBpf(true, mUid, true /* metered */);
386 
387             launchActivity();
388             assertTopState();
389             assertNetworkAccess(true, null);
390             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
391             assertNetworkAccessBlockedByBpf(false, mUid, true /* metered */);
392 
393             finishActivity();
394             assertProcessStateBelow(PROCESS_STATE_TOP_SLEEPING);
395             SystemClock.sleep(mProcessStateTransitionLongDelayMs);
396             assertNetworkAccess(false, null);
397             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
398             assertNetworkAccessBlockedByBpf(true, mUid, true /* metered */);
399 
400         } finally {
401             mMeterednessConfiguration.resetNetworkMeteredness();
402         }
403 
404         // Set to non-metered network
405         mMeterednessConfiguration.configureNetworkMeteredness(false);
406         mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
407                 true /* hasCapability */, NET_CAPABILITY_NOT_METERED);
408         try {
409             assertProcessStateBelow(PROCESS_STATE_TOP_SLEEPING);
410             assertNetworkAccess(false, null);
411             assertNetworkAccessBlockedByBpf(true, mUid, false /* metered */);
412 
413             launchActivity();
414             assertTopState();
415             assertNetworkAccess(true, null);
416             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
417             assertNetworkAccessBlockedByBpf(false, mUid, false /* metered */);
418 
419             finishActivity();
420             assertProcessStateBelow(PROCESS_STATE_TOP_SLEEPING);
421             SystemClock.sleep(mProcessStateTransitionLongDelayMs);
422             assertNetworkAccess(false, null);
423             mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
424             assertNetworkAccessBlockedByBpf(true, mUid, false /* metered */);
425         } finally {
426             mMeterednessConfiguration.resetNetworkMeteredness();
427         }
428     }
429 
430     // TODO: 1. test against VPN lockdown.
431     //       2. test against multiple networks.
432 }
433