Move the connectivity tests to frameworks/base/tests/net.
This will give us a good place to put all the networking tests. Fix: 31479480 Test: adb shell am instrument -w -e notClass com.android.server.connectivity.tethering.TetherInterfaceStateMachineTest 'com.android.frameworks.tests.net/android.support.test.runner.AndroidJUnitRunner' # PASS Change-Id: I4b389f7f4e33a996885b38670f585e58ca66f777
This commit is contained in:
2776
tests/net/java/com/android/server/ConnectivityServiceTest.java
Normal file
2776
tests/net/java/com/android/server/ConnectivityServiceTest.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.connectivity;
|
||||
|
||||
import static com.android.server.connectivity.MetricsTestUtil.aBool;
|
||||
import static com.android.server.connectivity.MetricsTestUtil.aByteArray;
|
||||
import static com.android.server.connectivity.MetricsTestUtil.aLong;
|
||||
import static com.android.server.connectivity.MetricsTestUtil.aString;
|
||||
import static com.android.server.connectivity.MetricsTestUtil.aType;
|
||||
import static com.android.server.connectivity.MetricsTestUtil.anInt;
|
||||
import static com.android.server.connectivity.MetricsTestUtil.anIntArray;
|
||||
import static com.android.server.connectivity.MetricsTestUtil.b;
|
||||
import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
|
||||
import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
|
||||
|
||||
import android.net.ConnectivityMetricsEvent;
|
||||
import android.net.metrics.ApfProgramEvent;
|
||||
import android.net.metrics.ApfStats;
|
||||
import android.net.metrics.DefaultNetworkEvent;
|
||||
import android.net.metrics.DhcpClientEvent;
|
||||
import android.net.metrics.DhcpErrorEvent;
|
||||
import android.net.metrics.DnsEvent;
|
||||
import android.net.metrics.IpManagerEvent;
|
||||
import android.net.metrics.IpReachabilityEvent;
|
||||
import android.net.metrics.NetworkEvent;
|
||||
import android.net.metrics.RaEvent;
|
||||
import android.net.metrics.ValidationProbeEvent;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class IpConnectivityEventBuilderTest extends TestCase {
|
||||
|
||||
public void testDefaultNetworkEventSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(DefaultNetworkEvent.class),
|
||||
anInt(102),
|
||||
anIntArray(1, 2, 3),
|
||||
anInt(101),
|
||||
aBool(true),
|
||||
aBool(false));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" default_network_event <",
|
||||
" network_id <",
|
||||
" network_id: 102",
|
||||
" >",
|
||||
" previous_network_id <",
|
||||
" network_id: 101",
|
||||
" >",
|
||||
" previous_network_ip_support: 1",
|
||||
" transport_types: 1",
|
||||
" transport_types: 2",
|
||||
" transport_types: 3",
|
||||
" >",
|
||||
" time_ms: 1",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
public void testDhcpClientEventSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(DhcpClientEvent.class),
|
||||
aString("wlan0"),
|
||||
aString("SomeState"),
|
||||
anInt(192));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" dhcp_event <",
|
||||
" duration_ms: 192",
|
||||
" error_code: 0",
|
||||
" if_name: \"wlan0\"",
|
||||
" state_transition: \"SomeState\"",
|
||||
" >",
|
||||
" time_ms: 1",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
public void testDhcpErrorEventSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(DhcpErrorEvent.class),
|
||||
aString("wlan0"),
|
||||
anInt(DhcpErrorEvent.L4_NOT_UDP));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" dhcp_event <",
|
||||
" duration_ms: 0",
|
||||
" error_code: 50397184",
|
||||
" if_name: \"wlan0\"",
|
||||
" state_transition: \"\"",
|
||||
" >",
|
||||
" time_ms: 1",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
public void testDnsEventSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(DnsEvent.class),
|
||||
anInt(101),
|
||||
aByteArray(b(1), b(1), b(2), b(1), b(1), b(1), b(2), b(2)),
|
||||
aByteArray(b(0), b(0), b(22), b(3), b(1), b(0), b(200), b(178)),
|
||||
anIntArray(3456, 267, 1230, 45, 2111, 450, 638, 1300));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" dns_lookup_batch <",
|
||||
" event_types: 1",
|
||||
" event_types: 1",
|
||||
" event_types: 2",
|
||||
" event_types: 1",
|
||||
" event_types: 1",
|
||||
" event_types: 1",
|
||||
" event_types: 2",
|
||||
" event_types: 2",
|
||||
" latencies_ms: 3456",
|
||||
" latencies_ms: 267",
|
||||
" latencies_ms: 1230",
|
||||
" latencies_ms: 45",
|
||||
" latencies_ms: 2111",
|
||||
" latencies_ms: 450",
|
||||
" latencies_ms: 638",
|
||||
" latencies_ms: 1300",
|
||||
" network_id <",
|
||||
" network_id: 101",
|
||||
" >",
|
||||
" return_codes: 0",
|
||||
" return_codes: 0",
|
||||
" return_codes: 22",
|
||||
" return_codes: 3",
|
||||
" return_codes: 1",
|
||||
" return_codes: 0",
|
||||
" return_codes: 200",
|
||||
" return_codes: 178",
|
||||
" >",
|
||||
" time_ms: 1",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
public void testIpManagerEventSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(IpManagerEvent.class),
|
||||
aString("wlan0"),
|
||||
anInt(IpManagerEvent.PROVISIONING_OK),
|
||||
aLong(5678));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" ip_provisioning_event <",
|
||||
" event_type: 1",
|
||||
" if_name: \"wlan0\"",
|
||||
" latency_ms: 5678",
|
||||
" >",
|
||||
" time_ms: 1",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
public void testIpReachabilityEventSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(IpReachabilityEvent.class),
|
||||
aString("wlan0"),
|
||||
anInt(IpReachabilityEvent.NUD_FAILED));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" ip_reachability_event <",
|
||||
" event_type: 512",
|
||||
" if_name: \"wlan0\"",
|
||||
" >",
|
||||
" time_ms: 1",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
public void testNetworkEventSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(NetworkEvent.class),
|
||||
anInt(100),
|
||||
anInt(5),
|
||||
aLong(20410));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" network_event <",
|
||||
" event_type: 5",
|
||||
" latency_ms: 20410",
|
||||
" network_id <",
|
||||
" network_id: 100",
|
||||
" >",
|
||||
" >",
|
||||
" time_ms: 1",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
public void testValidationProbeEventSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(ValidationProbeEvent.class),
|
||||
anInt(120),
|
||||
aLong(40730),
|
||||
anInt(ValidationProbeEvent.PROBE_HTTP),
|
||||
anInt(204));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" time_ms: 1",
|
||||
" validation_probe_event <",
|
||||
" latency_ms: 40730",
|
||||
" network_id <",
|
||||
" network_id: 120",
|
||||
" >",
|
||||
" probe_result: 204",
|
||||
" probe_type: 1",
|
||||
" >",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
public void testApfProgramEventSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(ApfProgramEvent.class),
|
||||
aLong(200),
|
||||
anInt(7),
|
||||
anInt(9),
|
||||
anInt(2048),
|
||||
anInt(3));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" apf_program_event <",
|
||||
" current_ras: 9",
|
||||
" drop_multicast: true",
|
||||
" filtered_ras: 7",
|
||||
" has_ipv4_addr: true",
|
||||
" lifetime: 200",
|
||||
" program_length: 2048",
|
||||
" >",
|
||||
" time_ms: 1",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
public void testApfStatsSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(ApfStats.class),
|
||||
aLong(45000),
|
||||
anInt(10),
|
||||
anInt(2),
|
||||
anInt(2),
|
||||
anInt(1),
|
||||
anInt(2),
|
||||
anInt(4),
|
||||
anInt(2048));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" apf_statistics <",
|
||||
" dropped_ras: 2",
|
||||
" duration_ms: 45000",
|
||||
" matching_ras: 2",
|
||||
" max_program_size: 2048",
|
||||
" parse_errors: 2",
|
||||
" program_updates: 4",
|
||||
" received_ras: 10",
|
||||
" zero_lifetime_ras: 1",
|
||||
" >",
|
||||
" time_ms: 1",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
public void testRaEventSerialization() {
|
||||
ConnectivityMetricsEvent ev = describeIpEvent(
|
||||
aType(RaEvent.class),
|
||||
aLong(2000),
|
||||
aLong(400),
|
||||
aLong(300),
|
||||
aLong(-1),
|
||||
aLong(1000),
|
||||
aLong(-1));
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" ra_event <",
|
||||
" dnssl_lifetime: -1",
|
||||
" prefix_preferred_lifetime: 300",
|
||||
" prefix_valid_lifetime: 400",
|
||||
" rdnss_lifetime: 1000",
|
||||
" route_info_lifetime: -1",
|
||||
" router_lifetime: 2000",
|
||||
" >",
|
||||
" time_ms: 1",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, ev);
|
||||
}
|
||||
|
||||
static void verifySerialization(String want, ConnectivityMetricsEvent... input) {
|
||||
try {
|
||||
byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
|
||||
IpConnectivityLog log = IpConnectivityLog.parseFrom(got);
|
||||
assertEquals(want, log.toString());
|
||||
} catch (Exception e) {
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
static String joinLines(String ... elems) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (String s : elems) {
|
||||
b.append(s);
|
||||
b.append("\n");
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (C) 2016, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.connectivity;
|
||||
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityMetricsEvent;
|
||||
import android.net.IIpConnectivityMetrics;
|
||||
import android.net.metrics.ApfProgramEvent;
|
||||
import android.net.metrics.ApfStats;
|
||||
import android.net.metrics.DefaultNetworkEvent;
|
||||
import android.net.metrics.DhcpClientEvent;
|
||||
import android.net.metrics.IpConnectivityLog;
|
||||
import android.net.metrics.IpManagerEvent;
|
||||
import android.net.metrics.IpReachabilityEvent;
|
||||
import android.net.metrics.RaEvent;
|
||||
import android.net.metrics.ValidationProbeEvent;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Base64;
|
||||
|
||||
import com.android.server.connectivity.metrics.IpConnectivityLogClass;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class IpConnectivityMetricsTest extends TestCase {
|
||||
static final IpReachabilityEvent FAKE_EV =
|
||||
new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED);
|
||||
|
||||
@Mock Context mCtx;
|
||||
@Mock IIpConnectivityMetrics mMockService;
|
||||
|
||||
IpConnectivityMetrics mService;
|
||||
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
|
||||
}
|
||||
|
||||
public void testLoggingEvents() throws Exception {
|
||||
IpConnectivityLog logger = new IpConnectivityLog(mMockService);
|
||||
|
||||
assertTrue(logger.log(1, FAKE_EV));
|
||||
assertTrue(logger.log(2, FAKE_EV));
|
||||
assertTrue(logger.log(3, FAKE_EV));
|
||||
|
||||
List<ConnectivityMetricsEvent> got = verifyEvents(3);
|
||||
assertEventsEqual(expectedEvent(1), got.get(0));
|
||||
assertEventsEqual(expectedEvent(2), got.get(1));
|
||||
assertEventsEqual(expectedEvent(3), got.get(2));
|
||||
}
|
||||
|
||||
public void testLoggingEventsWithMultipleCallers() throws Exception {
|
||||
IpConnectivityLog logger = new IpConnectivityLog(mMockService);
|
||||
|
||||
final int nCallers = 10;
|
||||
final int nEvents = 10;
|
||||
for (int n = 0; n < nCallers; n++) {
|
||||
final int i = n;
|
||||
new Thread() {
|
||||
public void run() {
|
||||
for (int j = 0; j < nEvents; j++) {
|
||||
assertTrue(logger.log(i * 100 + j, FAKE_EV));
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 100);
|
||||
Collections.sort(got, EVENT_COMPARATOR);
|
||||
Iterator<ConnectivityMetricsEvent> iter = got.iterator();
|
||||
for (int i = 0; i < nCallers; i++) {
|
||||
for (int j = 0; j < nEvents; j++) {
|
||||
int expectedTimestamp = i * 100 + j;
|
||||
assertEventsEqual(expectedEvent(expectedTimestamp), iter.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testBufferFlushing() {
|
||||
String output1 = getdump("flush");
|
||||
assertEquals("", output1);
|
||||
|
||||
new IpConnectivityLog(mService.impl).log(1, FAKE_EV);
|
||||
String output2 = getdump("flush");
|
||||
assertFalse("".equals(output2));
|
||||
|
||||
String output3 = getdump("flush");
|
||||
assertEquals("", output3);
|
||||
}
|
||||
|
||||
public void testRateLimiting() {
|
||||
final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
|
||||
final ApfProgramEvent ev = new ApfProgramEvent(0, 0, 0, 0, 0);
|
||||
final long fakeTimestamp = 1;
|
||||
|
||||
int attempt = 100; // More than burst quota, but less than buffer size.
|
||||
for (int i = 0; i < attempt; i++) {
|
||||
logger.log(ev);
|
||||
}
|
||||
|
||||
String output1 = getdump("flush");
|
||||
assertFalse("".equals(output1));
|
||||
|
||||
for (int i = 0; i < attempt; i++) {
|
||||
assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev));
|
||||
}
|
||||
|
||||
String output2 = getdump("flush");
|
||||
assertEquals("", output2);
|
||||
}
|
||||
|
||||
public void testEndToEndLogging() {
|
||||
IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
|
||||
|
||||
Parcelable[] events = {
|
||||
new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED),
|
||||
new DhcpClientEvent("wlan0", "SomeState", 192),
|
||||
new DefaultNetworkEvent(102, new int[]{1,2,3}, 101, true, false),
|
||||
new IpManagerEvent("wlan0", IpManagerEvent.PROVISIONING_OK, 5678),
|
||||
new ValidationProbeEvent(120, 40730, ValidationProbeEvent.PROBE_HTTP, 204),
|
||||
new ApfStats(45000, 10, 2, 2, 1, 2, 4, 2048),
|
||||
new RaEvent(2000, 400, 300, -1, 1000, -1)
|
||||
};
|
||||
|
||||
for (int i = 0; i < events.length; i++) {
|
||||
logger.log(100 * (i + 1), events[i]);
|
||||
}
|
||||
|
||||
String want = joinLines(
|
||||
"dropped_events: 0",
|
||||
"events <",
|
||||
" ip_reachability_event <",
|
||||
" event_type: 512",
|
||||
" if_name: \"wlan0\"",
|
||||
" >",
|
||||
" time_ms: 100",
|
||||
">",
|
||||
"events <",
|
||||
" dhcp_event <",
|
||||
" duration_ms: 192",
|
||||
" error_code: 0",
|
||||
" if_name: \"wlan0\"",
|
||||
" state_transition: \"SomeState\"",
|
||||
" >",
|
||||
" time_ms: 200",
|
||||
">",
|
||||
"events <",
|
||||
" default_network_event <",
|
||||
" network_id <",
|
||||
" network_id: 102",
|
||||
" >",
|
||||
" previous_network_id <",
|
||||
" network_id: 101",
|
||||
" >",
|
||||
" previous_network_ip_support: 1",
|
||||
" transport_types: 1",
|
||||
" transport_types: 2",
|
||||
" transport_types: 3",
|
||||
" >",
|
||||
" time_ms: 300",
|
||||
">",
|
||||
"events <",
|
||||
" ip_provisioning_event <",
|
||||
" event_type: 1",
|
||||
" if_name: \"wlan0\"",
|
||||
" latency_ms: 5678",
|
||||
" >",
|
||||
" time_ms: 400",
|
||||
">",
|
||||
"events <",
|
||||
" time_ms: 500",
|
||||
" validation_probe_event <",
|
||||
" latency_ms: 40730",
|
||||
" network_id <",
|
||||
" network_id: 120",
|
||||
" >",
|
||||
" probe_result: 204",
|
||||
" probe_type: 1",
|
||||
" >",
|
||||
">",
|
||||
"events <",
|
||||
" apf_statistics <",
|
||||
" dropped_ras: 2",
|
||||
" duration_ms: 45000",
|
||||
" matching_ras: 2",
|
||||
" max_program_size: 2048",
|
||||
" parse_errors: 2",
|
||||
" program_updates: 4",
|
||||
" received_ras: 10",
|
||||
" zero_lifetime_ras: 1",
|
||||
" >",
|
||||
" time_ms: 600",
|
||||
">",
|
||||
"events <",
|
||||
" ra_event <",
|
||||
" dnssl_lifetime: -1",
|
||||
" prefix_preferred_lifetime: 300",
|
||||
" prefix_valid_lifetime: 400",
|
||||
" rdnss_lifetime: 1000",
|
||||
" route_info_lifetime: -1",
|
||||
" router_lifetime: 2000",
|
||||
" >",
|
||||
" time_ms: 700",
|
||||
">",
|
||||
"version: 2");
|
||||
|
||||
verifySerialization(want, getdump("flush"));
|
||||
}
|
||||
|
||||
String getdump(String ... command) {
|
||||
StringWriter buffer = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(buffer);
|
||||
mService.impl.dump(null, writer, command);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
|
||||
ArgumentCaptor<ConnectivityMetricsEvent> captor =
|
||||
ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
|
||||
verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
|
||||
return captor.getAllValues();
|
||||
}
|
||||
|
||||
List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
|
||||
return verifyEvents(n, 10);
|
||||
}
|
||||
|
||||
static void verifySerialization(String want, String output) {
|
||||
try {
|
||||
byte[] got = Base64.decode(output, Base64.DEFAULT);
|
||||
IpConnectivityLogClass.IpConnectivityLog log =
|
||||
IpConnectivityLogClass.IpConnectivityLog.parseFrom(got);
|
||||
assertEquals(want, log.toString());
|
||||
} catch (Exception e) {
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
static String joinLines(String ... elems) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (String s : elems) {
|
||||
b.append(s).append("\n");
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
static ConnectivityMetricsEvent expectedEvent(int timestamp) {
|
||||
return new ConnectivityMetricsEvent((long)timestamp, 0, 0, FAKE_EV);
|
||||
}
|
||||
|
||||
/** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
|
||||
static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
|
||||
assertEquals(expected.timestamp, got.timestamp);
|
||||
assertEquals(expected.componentTag, got.componentTag);
|
||||
assertEquals(expected.eventTag, got.eventTag);
|
||||
assertEquals(expected.data, got.data);
|
||||
}
|
||||
|
||||
static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
|
||||
new Comparator<ConnectivityMetricsEvent>() {
|
||||
@Override
|
||||
public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
|
||||
return (int) (ev1.timestamp - ev2.timestamp);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (C) 2016, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.connectivity;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkMisc;
|
||||
import android.text.format.DateUtils;
|
||||
import com.android.internal.R;
|
||||
import com.android.server.ConnectivityService;
|
||||
import com.android.server.connectivity.NetworkNotificationManager;
|
||||
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
|
||||
import junit.framework.TestCase;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyBoolean;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.reset;
|
||||
|
||||
public class LingerMonitorTest extends TestCase {
|
||||
static final String CELLULAR = "CELLULAR";
|
||||
static final String WIFI = "WIFI";
|
||||
|
||||
static final long LOW_RATE_LIMIT = DateUtils.MINUTE_IN_MILLIS;
|
||||
static final long HIGH_RATE_LIMIT = 0;
|
||||
|
||||
static final int LOW_DAILY_LIMIT = 2;
|
||||
static final int HIGH_DAILY_LIMIT = 1000;
|
||||
|
||||
LingerMonitor mMonitor;
|
||||
|
||||
@Mock ConnectivityService mConnService;
|
||||
@Mock Context mCtx;
|
||||
@Mock NetworkMisc mMisc;
|
||||
@Mock NetworkNotificationManager mNotifier;
|
||||
@Mock Resources mResources;
|
||||
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mCtx.getResources()).thenReturn(mResources);
|
||||
when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity");
|
||||
when(mConnService.createNetworkMonitor(any(), any(), any(), any())).thenReturn(null);
|
||||
|
||||
mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
|
||||
}
|
||||
|
||||
public void testTransitions() {
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
NetworkAgentInfo nai1 = wifiNai(100);
|
||||
NetworkAgentInfo nai2 = cellNai(101);
|
||||
|
||||
assertTrue(mMonitor.isNotificationEnabled(nai1, nai2));
|
||||
assertFalse(mMonitor.isNotificationEnabled(nai2, nai1));
|
||||
}
|
||||
|
||||
public void testNotificationOnLinger() {
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNotification(from, to);
|
||||
}
|
||||
|
||||
public void testToastOnLinger() {
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyToast(from, to);
|
||||
}
|
||||
|
||||
public void testNotificationClearedAfterDisconnect() {
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNotification(from, to);
|
||||
|
||||
mMonitor.noteDisconnect(to);
|
||||
verify(mNotifier, times(1)).clearNotification(100);
|
||||
}
|
||||
|
||||
public void testNotificationClearedAfterSwitchingBack() {
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNotification(from, to);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(to, from);
|
||||
verify(mNotifier, times(1)).clearNotification(100);
|
||||
}
|
||||
|
||||
public void testUniqueToast() {
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyToast(from, to);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(to, from);
|
||||
verify(mNotifier, times(1)).clearNotification(100);
|
||||
|
||||
reset(mNotifier);
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNoNotifications();
|
||||
}
|
||||
|
||||
public void testMultipleNotifications() {
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
|
||||
NetworkAgentInfo wifi1 = wifiNai(100);
|
||||
NetworkAgentInfo wifi2 = wifiNai(101);
|
||||
NetworkAgentInfo cell = cellNai(102);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(wifi1, cell);
|
||||
verifyNotification(wifi1, cell);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(cell, wifi2);
|
||||
verify(mNotifier, times(1)).clearNotification(100);
|
||||
|
||||
reset(mNotifier);
|
||||
mMonitor.noteLingerDefaultNetwork(wifi2, cell);
|
||||
verifyNotification(wifi2, cell);
|
||||
}
|
||||
|
||||
public void testRateLimiting() throws InterruptedException {
|
||||
mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT);
|
||||
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
|
||||
NetworkAgentInfo wifi1 = wifiNai(100);
|
||||
NetworkAgentInfo wifi2 = wifiNai(101);
|
||||
NetworkAgentInfo wifi3 = wifiNai(102);
|
||||
NetworkAgentInfo cell = cellNai(103);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(wifi1, cell);
|
||||
verifyNotification(wifi1, cell);
|
||||
reset(mNotifier);
|
||||
|
||||
Thread.sleep(50);
|
||||
mMonitor.noteLingerDefaultNetwork(cell, wifi2);
|
||||
mMonitor.noteLingerDefaultNetwork(wifi2, cell);
|
||||
verifyNoNotifications();
|
||||
|
||||
Thread.sleep(50);
|
||||
mMonitor.noteLingerDefaultNetwork(cell, wifi3);
|
||||
mMonitor.noteLingerDefaultNetwork(wifi3, cell);
|
||||
verifyNoNotifications();
|
||||
}
|
||||
|
||||
public void testDailyLimiting() throws InterruptedException {
|
||||
mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT);
|
||||
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
|
||||
NetworkAgentInfo wifi1 = wifiNai(100);
|
||||
NetworkAgentInfo wifi2 = wifiNai(101);
|
||||
NetworkAgentInfo wifi3 = wifiNai(102);
|
||||
NetworkAgentInfo cell = cellNai(103);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(wifi1, cell);
|
||||
verifyNotification(wifi1, cell);
|
||||
reset(mNotifier);
|
||||
|
||||
Thread.sleep(50);
|
||||
mMonitor.noteLingerDefaultNetwork(cell, wifi2);
|
||||
mMonitor.noteLingerDefaultNetwork(wifi2, cell);
|
||||
verifyNotification(wifi2, cell);
|
||||
reset(mNotifier);
|
||||
|
||||
Thread.sleep(50);
|
||||
mMonitor.noteLingerDefaultNetwork(cell, wifi3);
|
||||
mMonitor.noteLingerDefaultNetwork(wifi3, cell);
|
||||
verifyNoNotifications();
|
||||
}
|
||||
|
||||
public void testUniqueNotification() {
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNotification(from, to);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(to, from);
|
||||
verify(mNotifier, times(1)).clearNotification(100);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNotification(from, to);
|
||||
}
|
||||
|
||||
public void testIgnoreNeverValidatedNetworks() {
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
from.everValidated = false;
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNoNotifications();
|
||||
}
|
||||
|
||||
public void testIgnoreCurrentlyValidatedNetworks() {
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
from.lastValidated = true;
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNoNotifications();
|
||||
}
|
||||
|
||||
public void testNoNotificationType() {
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
|
||||
setNotificationSwitch();
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNoNotifications();
|
||||
}
|
||||
|
||||
public void testNoTransitionToNotify() {
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE);
|
||||
setNotificationSwitch(transition(WIFI, CELLULAR));
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNoNotifications();
|
||||
}
|
||||
|
||||
public void testDifferentTransitionToNotify() {
|
||||
setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
|
||||
setNotificationSwitch(transition(CELLULAR, WIFI));
|
||||
NetworkAgentInfo from = wifiNai(100);
|
||||
NetworkAgentInfo to = cellNai(101);
|
||||
|
||||
mMonitor.noteLingerDefaultNetwork(from, to);
|
||||
verifyNoNotifications();
|
||||
}
|
||||
|
||||
void setNotificationSwitch(String... transitions) {
|
||||
when(mResources.getStringArray(R.array.config_networkNotifySwitches))
|
||||
.thenReturn(transitions);
|
||||
}
|
||||
|
||||
String transition(String from, String to) {
|
||||
return from + "-" + to;
|
||||
}
|
||||
|
||||
void setNotificationType(int type) {
|
||||
when(mResources.getInteger(R.integer.config_networkNotifySwitchType)).thenReturn(type);
|
||||
}
|
||||
|
||||
void verifyNoToast() {
|
||||
verify(mNotifier, never()).showToast(any(), any());
|
||||
}
|
||||
|
||||
void verifyNoNotification() {
|
||||
verify(mNotifier, never())
|
||||
.showNotification(anyInt(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
void verifyNoNotifications() {
|
||||
verifyNoToast();
|
||||
verifyNoNotification();
|
||||
}
|
||||
|
||||
void verifyToast(NetworkAgentInfo from, NetworkAgentInfo to) {
|
||||
verifyNoNotification();
|
||||
verify(mNotifier, times(1)).showToast(from, to);
|
||||
}
|
||||
|
||||
void verifyNotification(NetworkAgentInfo from, NetworkAgentInfo to) {
|
||||
verifyNoToast();
|
||||
verify(mNotifier, times(1)).showNotification(eq(from.network.netId),
|
||||
eq(NotificationType.NETWORK_SWITCH), eq(from), eq(to), any(), eq(true));
|
||||
}
|
||||
|
||||
NetworkAgentInfo nai(int netId, int transport, int networkType, String networkTypeName) {
|
||||
NetworkInfo info = new NetworkInfo(networkType, 0, networkTypeName, "");
|
||||
NetworkCapabilities caps = new NetworkCapabilities();
|
||||
caps.addCapability(0);
|
||||
caps.addTransportType(transport);
|
||||
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
|
||||
caps, 50, mCtx, null, mMisc, null, mConnService);
|
||||
nai.everValidated = true;
|
||||
return nai;
|
||||
}
|
||||
|
||||
NetworkAgentInfo wifiNai(int netId) {
|
||||
return nai(netId, NetworkCapabilities.TRANSPORT_WIFI,
|
||||
ConnectivityManager.TYPE_WIFI, WIFI);
|
||||
}
|
||||
|
||||
NetworkAgentInfo cellNai(int netId) {
|
||||
return nai(netId, NetworkCapabilities.TRANSPORT_CELLULAR,
|
||||
ConnectivityManager.TYPE_MOBILE, CELLULAR);
|
||||
}
|
||||
|
||||
public static class TestableLingerMonitor extends LingerMonitor {
|
||||
public TestableLingerMonitor(Context c, NetworkNotificationManager n, int l, long r) {
|
||||
super(c, n, l, r);
|
||||
}
|
||||
@Override protected PendingIntent createNotificationIntent() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.connectivity;
|
||||
|
||||
import android.net.ConnectivityMetricsEvent;
|
||||
import android.net.ConnectivityMetricsLogger;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
abstract public class MetricsTestUtil {
|
||||
private MetricsTestUtil() {
|
||||
}
|
||||
|
||||
static ConnectivityMetricsEvent ipEv(Parcelable p) {
|
||||
return ev(ConnectivityMetricsLogger.COMPONENT_TAG_CONNECTIVITY, p);
|
||||
}
|
||||
|
||||
static ConnectivityMetricsEvent telephonyEv() {
|
||||
return ev(ConnectivityMetricsLogger.COMPONENT_TAG_TELEPHONY, new Bundle());
|
||||
}
|
||||
|
||||
static ConnectivityMetricsEvent ev(int tag, Parcelable p) {
|
||||
return new ConnectivityMetricsEvent(1L, tag, 0, p);
|
||||
}
|
||||
|
||||
// Utiliy interface for describing the content of a Parcel. This relies on
|
||||
// the implementation defails of Parcelable and on the fact that the fully
|
||||
// qualified Parcelable class names are written as string in the Parcels.
|
||||
interface ParcelField {
|
||||
void write(Parcel p);
|
||||
}
|
||||
|
||||
static ConnectivityMetricsEvent describeIpEvent(ParcelField... fs) {
|
||||
Parcel p = Parcel.obtain();
|
||||
for (ParcelField f : fs) {
|
||||
f.write(p);
|
||||
}
|
||||
p.setDataPosition(0);
|
||||
return ipEv(p.readParcelable(ClassLoader.getSystemClassLoader()));
|
||||
}
|
||||
|
||||
static ParcelField aType(Class<?> c) {
|
||||
return new ParcelField() {
|
||||
public void write(Parcel p) {
|
||||
p.writeString(c.getName());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ParcelField aBool(boolean b) {
|
||||
return aByte((byte) (b ? 1 : 0));
|
||||
}
|
||||
|
||||
static ParcelField aByte(byte b) {
|
||||
return new ParcelField() {
|
||||
public void write(Parcel p) {
|
||||
p.writeByte(b);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ParcelField anInt(int i) {
|
||||
return new ParcelField() {
|
||||
public void write(Parcel p) {
|
||||
p.writeInt(i);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ParcelField aLong(long l) {
|
||||
return new ParcelField() {
|
||||
public void write(Parcel p) {
|
||||
p.writeLong(l);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ParcelField aString(String s) {
|
||||
return new ParcelField() {
|
||||
public void write(Parcel p) {
|
||||
p.writeString(s);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ParcelField aByteArray(byte... ary) {
|
||||
return new ParcelField() {
|
||||
public void write(Parcel p) {
|
||||
p.writeByteArray(ary);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ParcelField anIntArray(int... ary) {
|
||||
return new ParcelField() {
|
||||
public void write(Parcel p) {
|
||||
p.writeIntArray(ary);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static byte b(int i) {
|
||||
return (byte) i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) 2016, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.connectivity;
|
||||
|
||||
import android.net.ConnectivityManager.NetworkCallback;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.metrics.DnsEvent;
|
||||
import android.net.metrics.INetdEventListener;
|
||||
import android.net.metrics.IpConnectivityLog;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class NetdEventListenerServiceTest extends TestCase {
|
||||
|
||||
// TODO: read from NetdEventListenerService after this constant is read from system property
|
||||
static final int BATCH_SIZE = 100;
|
||||
static final int EVENT_TYPE = INetdEventListener.EVENT_GETADDRINFO;
|
||||
// TODO: read from INetdEventListener
|
||||
static final int RETURN_CODE = 1;
|
||||
|
||||
static final byte[] EVENT_TYPES = new byte[BATCH_SIZE];
|
||||
static final byte[] RETURN_CODES = new byte[BATCH_SIZE];
|
||||
static final int[] LATENCIES = new int[BATCH_SIZE];
|
||||
static {
|
||||
for (int i = 0; i < BATCH_SIZE; i++) {
|
||||
EVENT_TYPES[i] = EVENT_TYPE;
|
||||
RETURN_CODES[i] = RETURN_CODE;
|
||||
LATENCIES[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
NetdEventListenerService mNetdEventListenerService;
|
||||
|
||||
@Mock ConnectivityManager mCm;
|
||||
@Mock IpConnectivityLog mLog;
|
||||
ArgumentCaptor<NetworkCallback> mCallbackCaptor;
|
||||
ArgumentCaptor<DnsEvent> mEvCaptor;
|
||||
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
|
||||
mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
|
||||
mNetdEventListenerService = new NetdEventListenerService(mCm, mLog);
|
||||
|
||||
verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
|
||||
}
|
||||
|
||||
public void testOneBatch() throws Exception {
|
||||
log(105, LATENCIES);
|
||||
log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event
|
||||
|
||||
verifyLoggedEvents(new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
|
||||
|
||||
log(106, Arrays.copyOfRange(LATENCIES, BATCH_SIZE - 1, BATCH_SIZE));
|
||||
|
||||
mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor
|
||||
verifyLoggedEvents(
|
||||
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
|
||||
new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
|
||||
}
|
||||
|
||||
public void testSeveralBatches() throws Exception {
|
||||
log(105, LATENCIES);
|
||||
log(106, LATENCIES);
|
||||
log(105, LATENCIES);
|
||||
log(107, LATENCIES);
|
||||
|
||||
verifyLoggedEvents(
|
||||
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
|
||||
new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
|
||||
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
|
||||
new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
|
||||
}
|
||||
|
||||
public void testBatchAndNetworkLost() throws Exception {
|
||||
byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
|
||||
byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
|
||||
int[] latencies = Arrays.copyOf(LATENCIES, 20);
|
||||
|
||||
log(105, LATENCIES);
|
||||
log(105, latencies);
|
||||
mCallbackCaptor.getValue().onLost(new Network(105));
|
||||
log(105, LATENCIES);
|
||||
|
||||
verifyLoggedEvents(
|
||||
new DnsEvent(105, eventTypes, returnCodes, latencies),
|
||||
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
|
||||
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
|
||||
}
|
||||
|
||||
public void testConcurrentBatchesAndDumps() throws Exception {
|
||||
final long stop = System.currentTimeMillis() + 100;
|
||||
final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
|
||||
new Thread() {
|
||||
public void run() {
|
||||
while (System.currentTimeMillis() < stop) {
|
||||
mNetdEventListenerService.dump(pw);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
|
||||
logAsync(105, LATENCIES);
|
||||
logAsync(106, LATENCIES);
|
||||
logAsync(107, LATENCIES);
|
||||
|
||||
verifyLoggedEvents(500,
|
||||
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
|
||||
new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
|
||||
new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
|
||||
}
|
||||
|
||||
public void testConcurrentBatchesAndNetworkLoss() throws Exception {
|
||||
logAsync(105, LATENCIES);
|
||||
Thread.sleep(10L);
|
||||
// call onLost() asynchronously to logAsync's onDnsEvent() calls.
|
||||
mCallbackCaptor.getValue().onLost(new Network(105));
|
||||
|
||||
// do not verify unpredictable batch
|
||||
verify(mLog, timeout(500).times(1)).log(any());
|
||||
}
|
||||
|
||||
void log(int netId, int[] latencies) {
|
||||
for (int l : latencies) {
|
||||
mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l, null, null, 0,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
void logAsync(int netId, int[] latencies) {
|
||||
new Thread() {
|
||||
public void run() {
|
||||
log(netId, latencies);
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
void verifyLoggedEvents(DnsEvent... expected) {
|
||||
verifyLoggedEvents(0, expected);
|
||||
}
|
||||
|
||||
void verifyLoggedEvents(int wait, DnsEvent... expectedEvents) {
|
||||
verify(mLog, timeout(wait).times(expectedEvents.length)).log(mEvCaptor.capture());
|
||||
for (DnsEvent got : mEvCaptor.getAllValues()) {
|
||||
OptionalInt index = IntStream.range(0, expectedEvents.length)
|
||||
.filter(i -> eventsEqual(expectedEvents[i], got))
|
||||
.findFirst();
|
||||
// Don't match same expected event more than once.
|
||||
index.ifPresent(i -> expectedEvents[i] = null);
|
||||
assertTrue(index.isPresent());
|
||||
}
|
||||
}
|
||||
|
||||
/** equality function for DnsEvent to avoid overriding equals() and hashCode(). */
|
||||
static boolean eventsEqual(DnsEvent expected, DnsEvent got) {
|
||||
return (expected == got) || ((expected != null) && (got != null)
|
||||
&& (expected.netId == got.netId)
|
||||
&& Arrays.equals(expected.eventTypes, got.eventTypes)
|
||||
&& Arrays.equals(expected.returnCodes, got.returnCodes)
|
||||
&& Arrays.equals(expected.latenciesMs, got.latenciesMs));
|
||||
}
|
||||
}
|
||||
347
tests/net/java/com/android/server/connectivity/VpnTest.java
Normal file
347
tests/net/java/com/android/server/connectivity/VpnTest.java
Normal file
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.connectivity;
|
||||
|
||||
import static android.content.pm.UserInfo.FLAG_ADMIN;
|
||||
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
|
||||
import static android.content.pm.UserInfo.FLAG_PRIMARY;
|
||||
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
|
||||
import static org.mockito.AdditionalMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.net.NetworkInfo.DetailedState;
|
||||
import android.net.UidRange;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.os.Looper;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/**
|
||||
* Tests for {@link Vpn}.
|
||||
*
|
||||
* Build, install and run with:
|
||||
* runtest --path src/com/android/server/connectivity/VpnTest.java
|
||||
*/
|
||||
public class VpnTest extends AndroidTestCase {
|
||||
private static final String TAG = "VpnTest";
|
||||
|
||||
// Mock users
|
||||
static final UserInfo primaryUser = new UserInfo(27, "Primary", FLAG_ADMIN | FLAG_PRIMARY);
|
||||
static final UserInfo secondaryUser = new UserInfo(15, "Secondary", FLAG_ADMIN);
|
||||
static final UserInfo restrictedProfileA = new UserInfo(40, "RestrictedA", FLAG_RESTRICTED);
|
||||
static final UserInfo restrictedProfileB = new UserInfo(42, "RestrictedB", FLAG_RESTRICTED);
|
||||
static final UserInfo managedProfileA = new UserInfo(45, "ManagedA", FLAG_MANAGED_PROFILE);
|
||||
static {
|
||||
restrictedProfileA.restrictedProfileParentId = primaryUser.id;
|
||||
restrictedProfileB.restrictedProfileParentId = secondaryUser.id;
|
||||
managedProfileA.profileGroupId = primaryUser.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Names and UIDs for some fake packages. Important points:
|
||||
* - UID is ordered increasing.
|
||||
* - One pair of packages have consecutive UIDs.
|
||||
*/
|
||||
static final String[] PKGS = {"com.example", "org.example", "net.example", "web.vpn"};
|
||||
static final int[] PKG_UIDS = {66, 77, 78, 400};
|
||||
|
||||
// Mock packages
|
||||
static final Map<String, Integer> mPackages = new ArrayMap<>();
|
||||
static {
|
||||
for (int i = 0; i < PKGS.length; i++) {
|
||||
mPackages.put(PKGS[i], PKG_UIDS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Mock private Context mContext;
|
||||
@Mock private UserManager mUserManager;
|
||||
@Mock private PackageManager mPackageManager;
|
||||
@Mock private INetworkManagementService mNetService;
|
||||
@Mock private AppOpsManager mAppOps;
|
||||
@Mock private NotificationManager mNotificationManager;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
setMockedPackages(mPackages);
|
||||
when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
|
||||
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
|
||||
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
|
||||
when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
|
||||
.thenReturn(mNotificationManager);
|
||||
doNothing().when(mNetService).registerObserver(any());
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testRestrictedProfilesAreAddedToVpn() {
|
||||
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
|
||||
|
||||
final Vpn vpn = spyVpn(primaryUser.id);
|
||||
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
|
||||
null, null);
|
||||
|
||||
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
|
||||
UidRange.createForUser(primaryUser.id),
|
||||
UidRange.createForUser(restrictedProfileA.id)
|
||||
})), ranges);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testManagedProfilesAreNotAddedToVpn() {
|
||||
setMockedUsers(primaryUser, managedProfileA);
|
||||
|
||||
final Vpn vpn = spyVpn(primaryUser.id);
|
||||
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
|
||||
null, null);
|
||||
|
||||
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
|
||||
UidRange.createForUser(primaryUser.id)
|
||||
})), ranges);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testAddUserToVpnOnlyAddsOneUser() {
|
||||
setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
|
||||
|
||||
final Vpn vpn = spyVpn(primaryUser.id);
|
||||
final Set<UidRange> ranges = new ArraySet<>();
|
||||
vpn.addUserToRanges(ranges, primaryUser.id, null, null);
|
||||
|
||||
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
|
||||
UidRange.createForUser(primaryUser.id)
|
||||
})), ranges);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testUidWhiteAndBlacklist() throws Exception {
|
||||
final Vpn vpn = spyVpn(primaryUser.id);
|
||||
final UidRange user = UidRange.createForUser(primaryUser.id);
|
||||
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
|
||||
|
||||
// Whitelist
|
||||
final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
|
||||
Arrays.asList(packages), null);
|
||||
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
|
||||
new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]),
|
||||
new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2])
|
||||
})), allow);
|
||||
|
||||
// Blacklist
|
||||
final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
|
||||
null, Arrays.asList(packages));
|
||||
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
|
||||
new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
|
||||
new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
|
||||
/* Empty range between UIDS[1] and UIDS[2], should be excluded, */
|
||||
new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
|
||||
})), disallow);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testLockdownChangingPackage() throws Exception {
|
||||
final Vpn vpn = spyVpn(primaryUser.id);
|
||||
final UidRange user = UidRange.createForUser(primaryUser.id);
|
||||
|
||||
// Default state.
|
||||
assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
|
||||
|
||||
// Set always-on without lockdown.
|
||||
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
|
||||
assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
|
||||
|
||||
// Set always-on with lockdown.
|
||||
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
|
||||
verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
|
||||
new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
|
||||
new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
|
||||
}));
|
||||
assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
|
||||
assertUnblocked(vpn, user.start + PKG_UIDS[1]);
|
||||
|
||||
// Switch to another app.
|
||||
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
|
||||
verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
|
||||
new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
|
||||
new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
|
||||
}));
|
||||
verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
|
||||
new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
|
||||
new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
|
||||
}));
|
||||
assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
|
||||
assertUnblocked(vpn, user.start + PKG_UIDS[3]);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testLockdownAddingAProfile() throws Exception {
|
||||
final Vpn vpn = spyVpn(primaryUser.id);
|
||||
setMockedUsers(primaryUser);
|
||||
|
||||
// Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
|
||||
final UserInfo tempProfile = new UserInfo(restrictedProfileA.id, restrictedProfileA.name,
|
||||
restrictedProfileA.flags);
|
||||
tempProfile.restrictedProfileParentId = primaryUser.id;
|
||||
|
||||
final UidRange user = UidRange.createForUser(primaryUser.id);
|
||||
final UidRange profile = UidRange.createForUser(tempProfile.id);
|
||||
|
||||
// Set lockdown.
|
||||
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
|
||||
verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
|
||||
new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
|
||||
new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
|
||||
}));
|
||||
|
||||
// Verify restricted user isn't affected at first.
|
||||
assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
|
||||
|
||||
// Add the restricted user.
|
||||
setMockedUsers(primaryUser, tempProfile);
|
||||
vpn.onUserAdded(tempProfile.id);
|
||||
verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
|
||||
new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
|
||||
new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
|
||||
}));
|
||||
|
||||
// Remove the restricted user.
|
||||
tempProfile.partial = true;
|
||||
vpn.onUserRemoved(tempProfile.id);
|
||||
verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
|
||||
new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
|
||||
new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
|
||||
}));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testNotificationShownForAlwaysOnApp() {
|
||||
final Vpn vpn = spyVpn(primaryUser.id);
|
||||
final InOrder order = inOrder(vpn);
|
||||
setMockedUsers(primaryUser);
|
||||
|
||||
// Don't show a notification for regular disconnected states.
|
||||
vpn.updateState(DetailedState.DISCONNECTED, TAG);
|
||||
order.verify(vpn).updateAlwaysOnNotificationInternal(false);
|
||||
|
||||
// Start showing a notification for disconnected once always-on.
|
||||
vpn.setAlwaysOnPackage(PKGS[0], false);
|
||||
order.verify(vpn).updateAlwaysOnNotificationInternal(true);
|
||||
|
||||
// Stop showing the notification once connected.
|
||||
vpn.updateState(DetailedState.CONNECTED, TAG);
|
||||
order.verify(vpn).updateAlwaysOnNotificationInternal(false);
|
||||
|
||||
// Show the notification if we disconnect again.
|
||||
vpn.updateState(DetailedState.DISCONNECTED, TAG);
|
||||
order.verify(vpn).updateAlwaysOnNotificationInternal(true);
|
||||
|
||||
// Notification should be cleared after unsetting always-on package.
|
||||
vpn.setAlwaysOnPackage(null, false);
|
||||
order.verify(vpn).updateAlwaysOnNotificationInternal(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock some methods of vpn object.
|
||||
*/
|
||||
private Vpn spyVpn(@UserIdInt int userId) {
|
||||
final Vpn vpn = spy(new Vpn(Looper.myLooper(), mContext, mNetService, userId));
|
||||
|
||||
// Block calls to the NotificationManager or PendingIntent#getActivity.
|
||||
doNothing().when(vpn).updateAlwaysOnNotificationInternal(anyBoolean());
|
||||
return vpn;
|
||||
}
|
||||
|
||||
private static void assertBlocked(Vpn vpn, int... uids) {
|
||||
for (int uid : uids) {
|
||||
assertTrue("Uid " + uid + " should be blocked", vpn.isBlockingUid(uid));
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertUnblocked(Vpn vpn, int... uids) {
|
||||
for (int uid : uids) {
|
||||
assertFalse("Uid " + uid + " should not be blocked", vpn.isBlockingUid(uid));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate {@link #mUserManager} with a list of fake users.
|
||||
*/
|
||||
private void setMockedUsers(UserInfo... users) {
|
||||
final Map<Integer, UserInfo> userMap = new ArrayMap<>();
|
||||
for (UserInfo user : users) {
|
||||
userMap.put(user.id, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserManagerService#getUsers(boolean)
|
||||
*/
|
||||
doAnswer(invocation -> {
|
||||
final boolean excludeDying = (boolean) invocation.getArguments()[0];
|
||||
final ArrayList<UserInfo> result = new ArrayList<>(users.length);
|
||||
for (UserInfo ui : users) {
|
||||
if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
|
||||
result.add(ui);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}).when(mUserManager).getUsers(anyBoolean());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
final int id = (int) invocation.getArguments()[0];
|
||||
return userMap.get(id);
|
||||
}).when(mUserManager).getUserInfo(anyInt());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
final int id = (int) invocation.getArguments()[0];
|
||||
return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
|
||||
}).when(mUserManager).canHaveRestrictedProfile(anyInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
|
||||
*/
|
||||
private void setMockedPackages(final Map<String, Integer> packages) {
|
||||
try {
|
||||
doAnswer(invocation -> {
|
||||
final String appName = (String) invocation.getArguments()[0];
|
||||
final int userId = (int) invocation.getArguments()[1];
|
||||
return UserHandle.getUid(userId, packages.get(appName));
|
||||
}).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user