Move net unit tests to packages/Connectivity

Move the tests together with packages/Connectivity code, so both can be
moved to packages/modules/Connectivity together.

Also reorganize unit tests in a unit/ directory, as other tests
(integration/, common/ etc.) have been added in tests/net since they
were created. This makes the directory structure consistent.

Test: atest FrameworksNetTests
Bug: 187814163
Merged-In: I254ffd1c08ec058d594b4ea55cbae5505f8497cc

Change-Id: I254ffd1c08ec058d594b4ea55cbae5505f8497cc
This commit is contained in:
Remi NGUYEN VAN
2021-05-11 13:37:06 +00:00
parent 69afcd51db
commit 31022d6cda
145 changed files with 42447 additions and 0 deletions

8
tests/OWNERS Normal file
View File

@@ -0,0 +1,8 @@
set noparent
codewiz@google.com
jchalard@google.com
junyulai@google.com
lorenzo@google.com
reminv@google.com
satk@google.com

34
tests/TEST_MAPPING Normal file
View File

@@ -0,0 +1,34 @@
{
"presubmit": [
{
"name": "FrameworksNetIntegrationTests"
}
],
"postsubmit": [
{
"name": "FrameworksNetDeflakeTest"
}
],
"auto-postsubmit": [
// Test tag for automotive targets. These are only running in postsubmit so as to harden the
// automotive targets to avoid introducing additional test flake and build time. The plan for
// presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
// Additionally, this tag is used in targeted test suites to limit resource usage on the test
// infra during the hardening phase.
// TODO: this tag to be removed once the above is no longer an issue.
{
"name": "FrameworksNetTests"
},
{
"name": "FrameworksNetIntegrationTests"
},
{
"name": "FrameworksNetDeflakeTest"
}
],
"imports": [
{
"path": "packages/modules/Connectivity"
}
]
}

44
tests/common/Android.bp Normal file
View File

@@ -0,0 +1,44 @@
//
// Copyright (C) 2019 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.
//
// Tests in this folder are included both in unit tests and CTS.
// They must be fast and stable, and exercise public or test APIs.
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
java_library {
name: "FrameworksNetCommonTests",
srcs: ["java/**/*.java", "java/**/*.kt"],
static_libs: [
"androidx.core_core",
"androidx.test.rules",
"junit",
"mockito-target-minus-junit4",
"modules-utils-build",
"net-tests-utils",
"net-utils-framework-common",
"platform-test-annotations",
],
libs: [
"android.test.base.stubs",
],
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2021 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.
*/
import android.net.ParseException
import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.testutils.DevSdkIgnoreRule
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNull
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class ParseExceptionTest {
@get:Rule
val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.R)
@Test
fun testConstructor_WithCause() {
val testMessage = "Test message"
val base = Exception("Test")
val exception = ParseException(testMessage, base)
assertEquals(testMessage, exception.response)
assertEquals(base, exception.cause)
}
@Test
fun testConstructor_NoCause() {
val testMessage = "Test message"
val exception = ParseException(testMessage)
assertEquals(testMessage, exception.response)
assertNull(exception.cause)
}
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright (C) 2019 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 android.net
import android.os.Build
import androidx.test.filters.SmallTest
import com.android.modules.utils.build.SdkLevel
import com.android.testutils.assertParcelSane
import com.android.testutils.assertParcelingIsLossless
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
@SmallTest
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.Q)
class CaptivePortalDataTest {
@Rule @JvmField
val ignoreRule = DevSdkIgnoreRule()
private val data = CaptivePortalData.Builder()
.setRefreshTime(123L)
.setUserPortalUrl(Uri.parse("https://portal.example.com/test"))
.setVenueInfoUrl(Uri.parse("https://venue.example.com/test"))
.setSessionExtendable(true)
.setBytesRemaining(456L)
.setExpiryTime(789L)
.setCaptive(true)
.apply {
if (SdkLevel.isAtLeastS()) {
setVenueFriendlyName("venue friendly name")
}
}
.build()
private val dataFromPasspoint = CaptivePortalData.Builder()
.setCaptive(true)
.apply {
if (SdkLevel.isAtLeastS()) {
setVenueFriendlyName("venue friendly name")
setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
}
}
.build()
private fun makeBuilder() = CaptivePortalData.Builder(data)
@Test
fun testParcelUnparcel() {
val fieldCount = if (SdkLevel.isAtLeastS()) 10 else 7
assertParcelSane(data, fieldCount)
assertParcelSane(dataFromPasspoint, fieldCount)
assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
}
@Test
fun testEquals() {
assertEquals(data, makeBuilder().build())
assertNotEqualsAfterChange { it.setRefreshTime(456L) }
assertNotEqualsAfterChange { it.setUserPortalUrl(Uri.parse("https://example.com/")) }
assertNotEqualsAfterChange { it.setUserPortalUrl(null) }
assertNotEqualsAfterChange { it.setVenueInfoUrl(Uri.parse("https://example.com/")) }
assertNotEqualsAfterChange { it.setVenueInfoUrl(null) }
assertNotEqualsAfterChange { it.setSessionExtendable(false) }
assertNotEqualsAfterChange { it.setBytesRemaining(789L) }
assertNotEqualsAfterChange { it.setExpiryTime(12L) }
assertNotEqualsAfterChange { it.setCaptive(false) }
if (SdkLevel.isAtLeastS()) {
assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
assertNotEqualsAfterChange { it.setUserPortalUrl(
Uri.parse("https://tc.example.com/passpoint")) }
assertNotEqualsAfterChange { it.setUserPortalUrl(
Uri.parse("https://tc.example.com/passpoint"),
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
assertNotEqualsAfterChange { it.setUserPortalUrl(
Uri.parse("https://tc.example.com/other"),
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
assertNotEqualsAfterChange { it.setUserPortalUrl(
Uri.parse("https://tc.example.com/passpoint"),
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
assertNotEqualsAfterChange { it.setVenueInfoUrl(
Uri.parse("https://venue.example.com/passpoint")) }
assertNotEqualsAfterChange { it.setVenueInfoUrl(
Uri.parse("https://venue.example.com/other"),
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
assertNotEqualsAfterChange { it.setVenueInfoUrl(
Uri.parse("https://venue.example.com/passpoint"),
CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
}
}
@Test
fun testUserPortalUrl() {
assertEquals(Uri.parse("https://portal.example.com/test"), data.userPortalUrl)
}
@Test
fun testVenueInfoUrl() {
assertEquals(Uri.parse("https://venue.example.com/test"), data.venueInfoUrl)
}
@Test
fun testIsSessionExtendable() {
assertTrue(data.isSessionExtendable)
}
@Test
fun testByteLimit() {
assertEquals(456L, data.byteLimit)
// Test byteLimit unset.
assertEquals(-1L, CaptivePortalData.Builder(null).build().byteLimit)
}
@Test
fun testRefreshTimeMillis() {
assertEquals(123L, data.refreshTimeMillis)
}
@Test
fun testExpiryTimeMillis() {
assertEquals(789L, data.expiryTimeMillis)
// Test expiryTimeMillis unset.
assertEquals(-1L, CaptivePortalData.Builder(null).build().expiryTimeMillis)
}
@Test
fun testIsCaptive() {
assertTrue(data.isCaptive)
assertFalse(makeBuilder().setCaptive(false).build().isCaptive)
}
@Test @IgnoreUpTo(Build.VERSION_CODES.R)
fun testVenueFriendlyName() {
assertEquals("venue friendly name", data.venueFriendlyName)
}
@Test @IgnoreUpTo(Build.VERSION_CODES.R)
fun testGetVenueInfoUrlSource() {
assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
data.venueInfoUrlSource)
assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
dataFromPasspoint.venueInfoUrlSource)
}
@Test @IgnoreUpTo(Build.VERSION_CODES.R)
fun testGetUserPortalUrlSource() {
assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
data.userPortalUrlSource)
assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
dataFromPasspoint.userPortalUrlSource)
}
private fun CaptivePortalData.mutate(mutator: (CaptivePortalData.Builder) -> Unit) =
CaptivePortalData.Builder(this).apply { mutator(this) }.build()
private fun assertNotEqualsAfterChange(mutator: (CaptivePortalData.Builder) -> Unit) {
assertNotEquals(data, data.mutate(mutator))
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2019 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 android.net;
import static org.junit.Assert.assertEquals;
import android.os.Build;
import android.os.RemoteException;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class CaptivePortalTest {
@Rule
public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
private static final int DEFAULT_TIMEOUT_MS = 5000;
private static final String TEST_PACKAGE_NAME = "com.google.android.test";
private final class MyCaptivePortalImpl extends ICaptivePortal.Stub {
int mCode = -1;
String mPackageName = null;
@Override
public void appResponse(final int response) throws RemoteException {
mCode = response;
}
@Override
public void appRequest(final int request) throws RemoteException {
mCode = request;
}
// This is only @Override on R-
public void logEvent(int eventId, String packageName) throws RemoteException {
mCode = eventId;
mPackageName = packageName;
}
}
private interface TestFunctor {
void useCaptivePortal(CaptivePortal o);
}
private MyCaptivePortalImpl runCaptivePortalTest(TestFunctor f) {
final MyCaptivePortalImpl cp = new MyCaptivePortalImpl();
f.useCaptivePortal(new CaptivePortal(cp.asBinder()));
return cp;
}
@Test
public void testReportCaptivePortalDismissed() {
final MyCaptivePortalImpl result =
runCaptivePortalTest(c -> c.reportCaptivePortalDismissed());
assertEquals(result.mCode, CaptivePortal.APP_RETURN_DISMISSED);
}
@Test
public void testIgnoreNetwork() {
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.ignoreNetwork());
assertEquals(result.mCode, CaptivePortal.APP_RETURN_UNWANTED);
}
@Test
public void testUseNetwork() {
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.useNetwork());
assertEquals(result.mCode, CaptivePortal.APP_RETURN_WANTED_AS_IS);
}
@IgnoreUpTo(Build.VERSION_CODES.Q)
@Test
public void testReevaluateNetwork() {
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.reevaluateNetwork());
assertEquals(result.mCode, CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED);
}
@IgnoreUpTo(Build.VERSION_CODES.R)
@Test
public void testLogEvent() {
/**
* From S testLogEvent is expected to do nothing but shouldn't crash (the API
* logEvent has been deprecated).
*/
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
0,
TEST_PACKAGE_NAME));
}
@IgnoreAfter(Build.VERSION_CODES.R)
@Test
public void testLogEvent_UntilR() {
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
42, TEST_PACKAGE_NAME));
assertEquals(result.mCode, 42);
assertEquals(result.mPackageName, TEST_PACKAGE_NAME);
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2020 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 android.net;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
/**
* A simple class that tests dependencies to java standard tools from the
* Network stack. These tests are not meant to be comprehensive tests of
* the relevant APIs : such tests belong in the relevant test suite for
* these dependencies. Instead, this just makes sure coverage is present
* by calling the methods in the exact way (or a representative way of how)
* they are called in the network stack.
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DependenciesTest {
// Used to in ipmemorystore's RegularMaintenanceJobService to convert
// 24 hours into seconds
@Test
public void testTimeUnit() {
final int hours = 24;
final long inSeconds = TimeUnit.HOURS.toMillis(hours);
assertEquals(inSeconds, hours * 60 * 60 * 1000);
}
private byte[] makeTrivialArray(final int size) {
final byte[] src = new byte[size];
for (int i = 0; i < size; ++i) {
src[i] = (byte) i;
}
return src;
}
// Used in ApfFilter to find an IP address from a byte array
@Test
public void testArrays() {
final int size = 128;
final byte[] src = makeTrivialArray(size);
// Test copy
final int copySize = 16;
final int offset = 24;
final byte[] expected = new byte[copySize];
for (int i = 0; i < copySize; ++i) {
expected[i] = (byte) (offset + i);
}
final byte[] copy = Arrays.copyOfRange(src, offset, offset + copySize);
assertArrayEquals(expected, copy);
assertArrayEquals(new byte[0], Arrays.copyOfRange(src, size, size));
}
// Used mainly in the Dhcp code
@Test
public void testCopyOf() {
final byte[] src = makeTrivialArray(128);
final byte[] copy = Arrays.copyOf(src, src.length);
assertArrayEquals(src, copy);
assertFalse(src == copy);
assertArrayEquals(new byte[0], Arrays.copyOf(src, 0));
final int excess = 16;
final byte[] biggerCopy = Arrays.copyOf(src, src.length + excess);
for (int i = src.length; i < src.length + excess; ++i) {
assertEquals(0, biggerCopy[i]);
}
for (int i = src.length - 1; i >= 0; --i) {
assertEquals(src[i], biggerCopy[i]);
}
}
// Used mainly in DnsUtils but also various other places
@Test
public void testAsList() {
final int size = 24;
final Object[] src = new Object[size];
final ArrayList<Object> expected = new ArrayList<>(size);
for (int i = 0; i < size; ++i) {
final Object o = new Object();
src[i] = o;
expected.add(o);
}
assertEquals(expected, Arrays.asList(src));
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright (C) 2009 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 android.net;
import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTL;
import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.annotation.Nullable;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.Inet4Address;
import java.net.InetAddress;
@RunWith(AndroidJUnit4.class)
public class DhcpInfoTest {
private static final String STR_ADDR1 = "255.255.255.255";
private static final String STR_ADDR2 = "127.0.0.1";
private static final String STR_ADDR3 = "192.168.1.1";
private static final String STR_ADDR4 = "192.168.1.0";
private static final int LEASE_TIME = 9999;
private int ipToInteger(String ipString) throws Exception {
return inet4AddressToIntHTL((Inet4Address) InetAddress.getByName(ipString));
}
private DhcpInfo createDhcpInfoObject() throws Exception {
final DhcpInfo dhcpInfo = new DhcpInfo();
dhcpInfo.ipAddress = ipToInteger(STR_ADDR1);
dhcpInfo.gateway = ipToInteger(STR_ADDR2);
dhcpInfo.netmask = ipToInteger(STR_ADDR3);
dhcpInfo.dns1 = ipToInteger(STR_ADDR4);
dhcpInfo.dns2 = ipToInteger(STR_ADDR4);
dhcpInfo.serverAddress = ipToInteger(STR_ADDR2);
dhcpInfo.leaseDuration = LEASE_TIME;
return dhcpInfo;
}
@Test
public void testConstructor() {
new DhcpInfo();
}
@Test
public void testToString() throws Exception {
final String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 "
+ "dns1 0.0.0.0 dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds";
DhcpInfo dhcpInfo = new DhcpInfo();
// Test default string.
assertEquals(expectedDefault, dhcpInfo.toString());
dhcpInfo = createDhcpInfoObject();
final String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask "
+ STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server "
+ STR_ADDR2 + " lease " + LEASE_TIME + " seconds";
// Test with new values
assertEquals(expected, dhcpInfo.toString());
}
private boolean dhcpInfoEquals(@Nullable DhcpInfo left, @Nullable DhcpInfo right) {
if (left == null && right == null) return true;
if (left == null || right == null) return false;
return left.ipAddress == right.ipAddress
&& left.gateway == right.gateway
&& left.netmask == right.netmask
&& left.dns1 == right.dns1
&& left.dns2 == right.dns2
&& left.serverAddress == right.serverAddress
&& left.leaseDuration == right.leaseDuration;
}
@Test
public void testParcelDhcpInfo() throws Exception {
// Cannot use assertParcelSane() here because this requires .equals() to work as
// defined, but DhcpInfo has a different legacy behavior that we cannot change.
final DhcpInfo dhcpInfo = createDhcpInfoObject();
assertFieldCountEquals(7, DhcpInfo.class);
final DhcpInfo dhcpInfoRoundTrip = parcelingRoundTrip(dhcpInfo);
assertTrue(dhcpInfoEquals(null, null));
assertFalse(dhcpInfoEquals(null, dhcpInfoRoundTrip));
assertFalse(dhcpInfoEquals(dhcpInfo, null));
assertTrue(dhcpInfoEquals(dhcpInfo, dhcpInfoRoundTrip));
}
}

View File

@@ -0,0 +1,374 @@
/*
* Copyright (C) 2014 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 android.net;
import static com.android.testutils.MiscAsserts.assertEqualBothWays;
import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.util.Random;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class IpPrefixTest {
private static InetAddress address(String addr) {
return InetAddress.parseNumericAddress(addr);
}
// Explicitly cast everything to byte because "error: possible loss of precision".
private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4};
private static final byte[] IPV6_BYTES = {
(byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
(byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0
};
@Test
public void testConstructor() {
IpPrefix p;
try {
p = new IpPrefix((byte[]) null, 9);
fail("Expected NullPointerException: null byte array");
} catch (RuntimeException expected) { }
try {
p = new IpPrefix((InetAddress) null, 10);
fail("Expected NullPointerException: null InetAddress");
} catch (RuntimeException expected) { }
try {
p = new IpPrefix((String) null);
fail("Expected NullPointerException: null String");
} catch (RuntimeException expected) { }
try {
byte[] b2 = {1, 2, 3, 4, 5};
p = new IpPrefix(b2, 29);
fail("Expected IllegalArgumentException: invalid array length");
} catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.4");
fail("Expected IllegalArgumentException: no prefix length");
} catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.4/");
fail("Expected IllegalArgumentException: empty prefix length");
} catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("foo/32");
fail("Expected IllegalArgumentException: invalid address");
} catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1/32");
fail("Expected IllegalArgumentException: deprecated IPv4 format");
} catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.256/32");
fail("Expected IllegalArgumentException: invalid IPv4 address");
} catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("foo/32");
fail("Expected IllegalArgumentException: non-address");
} catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("f00:::/32");
fail("Expected IllegalArgumentException: invalid IPv6 address");
} catch (IllegalArgumentException expected) { }
p = new IpPrefix("/64");
assertEquals("::/64", p.toString());
p = new IpPrefix("/128");
assertEquals("::1/128", p.toString());
p = new IpPrefix("[2001:db8::123]/64");
assertEquals("2001:db8::/64", p.toString());
}
@Test
public void testTruncation() {
IpPrefix p;
p = new IpPrefix(IPV4_BYTES, 32);
assertEquals("192.0.2.4/32", p.toString());
p = new IpPrefix(IPV4_BYTES, 29);
assertEquals("192.0.2.0/29", p.toString());
p = new IpPrefix(IPV4_BYTES, 8);
assertEquals("192.0.0.0/8", p.toString());
p = new IpPrefix(IPV4_BYTES, 0);
assertEquals("0.0.0.0/0", p.toString());
try {
p = new IpPrefix(IPV4_BYTES, 33);
fail("Expected IllegalArgumentException: invalid prefix length");
} catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV4_BYTES, 128);
fail("Expected IllegalArgumentException: invalid prefix length");
} catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV4_BYTES, -1);
fail("Expected IllegalArgumentException: negative prefix length");
} catch (RuntimeException expected) { }
p = new IpPrefix(IPV6_BYTES, 128);
assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString());
p = new IpPrefix(IPV6_BYTES, 122);
assertEquals("2001:db8:dead:beef:f00::80/122", p.toString());
p = new IpPrefix(IPV6_BYTES, 64);
assertEquals("2001:db8:dead:beef::/64", p.toString());
p = new IpPrefix(IPV6_BYTES, 3);
assertEquals("2000::/3", p.toString());
p = new IpPrefix(IPV6_BYTES, 0);
assertEquals("::/0", p.toString());
try {
p = new IpPrefix(IPV6_BYTES, -1);
fail("Expected IllegalArgumentException: negative prefix length");
} catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV6_BYTES, 129);
fail("Expected IllegalArgumentException: negative prefix length");
} catch (RuntimeException expected) { }
}
@Test
public void testEquals() {
IpPrefix p1, p2;
p1 = new IpPrefix("192.0.2.251/23");
p2 = new IpPrefix(new byte[]{(byte) 192, (byte) 0, (byte) 2, (byte) 251}, 23);
assertEqualBothWays(p1, p2);
p1 = new IpPrefix("192.0.2.5/23");
assertEqualBothWays(p1, p2);
p1 = new IpPrefix("192.0.2.5/24");
assertNotEqualEitherWay(p1, p2);
p1 = new IpPrefix("192.0.4.5/23");
assertNotEqualEitherWay(p1, p2);
p1 = new IpPrefix("2001:db8:dead:beef:f00::80/122");
p2 = new IpPrefix(IPV6_BYTES, 122);
assertEquals("2001:db8:dead:beef:f00::80/122", p2.toString());
assertEqualBothWays(p1, p2);
p1 = new IpPrefix("2001:db8:dead:beef:f00::bf/122");
assertEqualBothWays(p1, p2);
p1 = new IpPrefix("2001:db8:dead:beef:f00::8:0/123");
assertNotEqualEitherWay(p1, p2);
p1 = new IpPrefix("2001:db8:dead:beef::/122");
assertNotEqualEitherWay(p1, p2);
// 192.0.2.4/32 != c000:0204::/32.
byte[] ipv6bytes = new byte[16];
System.arraycopy(IPV4_BYTES, 0, ipv6bytes, 0, IPV4_BYTES.length);
p1 = new IpPrefix(ipv6bytes, 32);
assertEqualBothWays(p1, new IpPrefix("c000:0204::/32"));
p2 = new IpPrefix(IPV4_BYTES, 32);
assertNotEqualEitherWay(p1, p2);
}
@Test
public void testContainsInetAddress() {
IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
assertTrue(p.contains(address("2001:db8:f00::ace:d00c")));
assertTrue(p.contains(address("2001:db8:f00::ace:d00d")));
assertFalse(p.contains(address("2001:db8:f00::ace:d00e")));
assertFalse(p.contains(address("2001:db8:f00::bad:d00d")));
assertFalse(p.contains(address("2001:4868:4860::8888")));
assertFalse(p.contains(address("8.8.8.8")));
p = new IpPrefix("192.0.2.0/23");
assertTrue(p.contains(address("192.0.2.43")));
assertTrue(p.contains(address("192.0.3.21")));
assertFalse(p.contains(address("192.0.0.21")));
assertFalse(p.contains(address("8.8.8.8")));
assertFalse(p.contains(address("2001:4868:4860::8888")));
IpPrefix ipv6Default = new IpPrefix("::/0");
assertTrue(ipv6Default.contains(address("2001:db8::f00")));
assertFalse(ipv6Default.contains(address("192.0.2.1")));
IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
assertTrue(ipv4Default.contains(address("255.255.255.255")));
assertTrue(ipv4Default.contains(address("192.0.2.1")));
assertFalse(ipv4Default.contains(address("2001:db8::f00")));
}
@Test
public void testContainsIpPrefix() {
assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("0.0.0.0/0")));
assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/0")));
assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/8")));
assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/24")));
assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/23")));
assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.2.3.4/8")));
assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.254.12.9/8")));
assertTrue(new IpPrefix("1.2.3.4/21").containsPrefix(new IpPrefix("1.2.3.4/21")));
assertTrue(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.4/32")));
assertTrue(new IpPrefix("1.2.3.4/20").containsPrefix(new IpPrefix("1.2.3.0/24")));
assertFalse(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.5/32")));
assertFalse(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("2.2.3.4/8")));
assertFalse(new IpPrefix("0.0.0.0/16").containsPrefix(new IpPrefix("0.0.0.0/15")));
assertFalse(new IpPrefix("100.0.0.0/8").containsPrefix(new IpPrefix("99.0.0.0/8")));
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("::/0")));
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/1")));
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("3d8a:661:a0::770/8")));
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/8")));
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/64")));
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/113")));
assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/128")));
assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
new IpPrefix("2001:db8:f00::ace:d00d/64")));
assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
new IpPrefix("2001:db8:f00::ace:d00d/120")));
assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
new IpPrefix("2001:db8:f00::ace:d00d/32")));
assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
new IpPrefix("2006:db8:f00::ace:d00d/96")));
assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
new IpPrefix("2001:db8:f00::ace:d00d/128")));
assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/100").containsPrefix(
new IpPrefix("2001:db8:f00::ace:ccaf/110")));
assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
new IpPrefix("2001:db8:f00::ace:d00e/128")));
assertFalse(new IpPrefix("::/30").containsPrefix(new IpPrefix("::/29")));
}
@Test
public void testHashCode() {
IpPrefix p = new IpPrefix(new byte[4], 0);
Random random = new Random();
for (int i = 0; i < 100; i++) {
final IpPrefix oldP = p;
if (random.nextBoolean()) {
// IPv4.
byte[] b = new byte[4];
random.nextBytes(b);
p = new IpPrefix(b, random.nextInt(33));
} else {
// IPv6.
byte[] b = new byte[16];
random.nextBytes(b);
p = new IpPrefix(b, random.nextInt(129));
}
if (p.equals(oldP)) {
assertEquals(p.hashCode(), oldP.hashCode());
}
if (p.hashCode() != oldP.hashCode()) {
assertNotEquals(p, oldP);
}
}
}
@Test
public void testHashCodeIsNotConstant() {
IpPrefix[] prefixes = {
new IpPrefix("2001:db8:f00::ace:d00d/127"),
new IpPrefix("192.0.2.0/23"),
new IpPrefix("::/0"),
new IpPrefix("0.0.0.0/0"),
};
for (int i = 0; i < prefixes.length; i++) {
for (int j = i + 1; j < prefixes.length; j++) {
assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
}
}
}
@Test
public void testMappedAddressesAreBroken() {
// 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress,
// we are unable to comprehend that.
byte[] ipv6bytes = {
(byte) 0, (byte) 0, (byte) 0, (byte) 0,
(byte) 0, (byte) 0, (byte) 0, (byte) 0,
(byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff,
(byte) 192, (byte) 0, (byte) 2, (byte) 0};
IpPrefix p = new IpPrefix(ipv6bytes, 120);
assertEquals(16, p.getRawAddress().length); // Fine.
assertArrayEquals(ipv6bytes, p.getRawAddress()); // Fine.
// Broken.
assertEquals("192.0.2.0/120", p.toString());
assertEquals(InetAddress.parseNumericAddress("192.0.2.0"), p.getAddress());
}
@Test
public void testParceling() {
IpPrefix p;
p = new IpPrefix("2001:4860:db8::/64");
assertParcelingIsLossless(p);
assertTrue(p.isIPv6());
p = new IpPrefix("192.0.2.0/25");
assertParcelingIsLossless(p);
assertTrue(p.isIPv4());
assertFieldCountEquals(2, IpPrefix.class);
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2020 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 android.net
import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS
import android.net.InvalidPacketException.ERROR_INVALID_PORT
import android.os.Build
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import java.net.InetAddress
import java.util.Arrays
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SmallTest
class KeepalivePacketDataTest {
@Rule @JvmField
val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
private val INVALID_PORT = 65537
private val TEST_DST_PORT = 4244
private val TEST_SRC_PORT = 4243
private val TESTBYTES = byteArrayOf(12, 31, 22, 44)
private val TEST_SRC_ADDRV4 = "198.168.0.2".address()
private val TEST_DST_ADDRV4 = "198.168.0.1".address()
private val TEST_ADDRV6 = "2001:db8::1".address()
private fun String.address() = InetAddresses.parseNumericAddress(this)
// Add for test because constructor of KeepalivePacketData is protected.
private inner class TestKeepalivePacketData(
srcAddress: InetAddress? = TEST_SRC_ADDRV4,
srcPort: Int = TEST_SRC_PORT,
dstAddress: InetAddress? = TEST_DST_ADDRV4,
dstPort: Int = TEST_DST_PORT,
data: ByteArray = TESTBYTES
) : KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, data)
@Test
@IgnoreUpTo(Build.VERSION_CODES.Q)
fun testConstructor() {
var data: TestKeepalivePacketData
try {
data = TestKeepalivePacketData(srcAddress = null)
fail("Null src address should cause exception")
} catch (e: InvalidPacketException) {
assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
}
try {
data = TestKeepalivePacketData(dstAddress = null)
fail("Null dst address should cause exception")
} catch (e: InvalidPacketException) {
assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
}
try {
data = TestKeepalivePacketData(dstAddress = TEST_ADDRV6)
fail("Ip family mismatched should cause exception")
} catch (e: InvalidPacketException) {
assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
}
try {
data = TestKeepalivePacketData(srcPort = INVALID_PORT)
fail("Invalid srcPort should cause exception")
} catch (e: InvalidPacketException) {
assertEquals(e.error, ERROR_INVALID_PORT)
}
try {
data = TestKeepalivePacketData(dstPort = INVALID_PORT)
fail("Invalid dstPort should cause exception")
} catch (e: InvalidPacketException) {
assertEquals(e.error, ERROR_INVALID_PORT)
}
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.Q)
fun testSrcAddress() = assertEquals(TEST_SRC_ADDRV4, TestKeepalivePacketData().srcAddress)
@Test
@IgnoreUpTo(Build.VERSION_CODES.Q)
fun testDstAddress() = assertEquals(TEST_DST_ADDRV4, TestKeepalivePacketData().dstAddress)
@Test
@IgnoreUpTo(Build.VERSION_CODES.Q)
fun testSrcPort() = assertEquals(TEST_SRC_PORT, TestKeepalivePacketData().srcPort)
@Test
@IgnoreUpTo(Build.VERSION_CODES.Q)
fun testDstPort() = assertEquals(TEST_DST_PORT, TestKeepalivePacketData().dstPort)
@Test
@IgnoreUpTo(Build.VERSION_CODES.Q)
fun testPacket() = assertTrue(Arrays.equals(TESTBYTES, TestKeepalivePacketData().packet))
}

View File

@@ -0,0 +1,518 @@
/*
* Copyright (C) 2013 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 android.net;
import static android.system.OsConstants.IFA_F_DADFAILED;
import static android.system.OsConstants.IFA_F_DEPRECATED;
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
import static android.system.OsConstants.IFA_F_PERMANENT;
import static android.system.OsConstants.IFA_F_TEMPORARY;
import static android.system.OsConstants.IFA_F_TENTATIVE;
import static android.system.OsConstants.RT_SCOPE_HOST;
import static android.system.OsConstants.RT_SCOPE_LINK;
import static android.system.OsConstants.RT_SCOPE_SITE;
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
import static com.android.testutils.MiscAsserts.assertEqualBothWays;
import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.os.Build;
import android.os.SystemClock;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Arrays;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class LinkAddressTest {
@Rule
public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
private static final String V4 = "192.0.2.1";
private static final String V6 = "2001:db8::1";
private static final InetAddress V4_ADDRESS = InetAddresses.parseNumericAddress(V4);
private static final InetAddress V6_ADDRESS = InetAddresses.parseNumericAddress(V6);
@Test
public void testConstants() {
// RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
assertNotEquals(0, RT_SCOPE_HOST);
assertNotEquals(0, RT_SCOPE_LINK);
assertNotEquals(0, RT_SCOPE_SITE);
assertNotEquals(0, IFA_F_DEPRECATED);
assertNotEquals(0, IFA_F_PERMANENT);
assertNotEquals(0, IFA_F_TENTATIVE);
}
@Test
public void testConstructors() throws SocketException {
LinkAddress address;
// Valid addresses work as expected.
address = new LinkAddress(V4_ADDRESS, 25);
assertEquals(V4_ADDRESS, address.getAddress());
assertEquals(25, address.getPrefixLength());
assertEquals(0, address.getFlags());
assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
assertTrue(address.isIpv4());
address = new LinkAddress(V6_ADDRESS, 127);
assertEquals(V6_ADDRESS, address.getAddress());
assertEquals(127, address.getPrefixLength());
assertEquals(0, address.getFlags());
assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
assertTrue(address.isIpv6());
// Nonsensical flags/scopes or combinations thereof are acceptable.
address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
assertEquals(V6_ADDRESS, address.getAddress());
assertEquals(64, address.getPrefixLength());
assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
assertEquals(RT_SCOPE_LINK, address.getScope());
assertTrue(address.isIpv6());
address = new LinkAddress(V4 + "/23", 123, 456);
assertEquals(V4_ADDRESS, address.getAddress());
assertEquals(23, address.getPrefixLength());
assertEquals(123, address.getFlags());
assertEquals(456, address.getScope());
assertTrue(address.isIpv4());
address = new LinkAddress("/64", 1 /* flags */, 2 /* scope */);
assertEquals(Inet6Address.LOOPBACK, address.getAddress());
assertEquals(64, address.getPrefixLength());
assertEquals(1, address.getFlags());
assertEquals(2, address.getScope());
assertTrue(address.isIpv6());
address = new LinkAddress("[2001:db8::123]/64", 3 /* flags */, 4 /* scope */);
assertEquals(InetAddresses.parseNumericAddress("2001:db8::123"), address.getAddress());
assertEquals(64, address.getPrefixLength());
assertEquals(3, address.getFlags());
assertEquals(4, address.getScope());
assertTrue(address.isIpv6());
// InterfaceAddress doesn't have a constructor. Fetch some from an interface.
List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
// We expect to find 127.0.0.1/8 and ::1/128, in any order.
LinkAddress ipv4Loopback, ipv6Loopback;
assertEquals(2, addrs.size());
if (addrs.get(0).getAddress() instanceof Inet4Address) {
ipv4Loopback = new LinkAddress(addrs.get(0));
ipv6Loopback = new LinkAddress(addrs.get(1));
} else {
ipv4Loopback = new LinkAddress(addrs.get(1));
ipv6Loopback = new LinkAddress(addrs.get(0));
}
assertEquals(InetAddresses.parseNumericAddress("127.0.0.1"), ipv4Loopback.getAddress());
assertEquals(8, ipv4Loopback.getPrefixLength());
assertEquals(InetAddresses.parseNumericAddress("::1"), ipv6Loopback.getAddress());
assertEquals(128, ipv6Loopback.getPrefixLength());
// Null addresses are rejected.
try {
address = new LinkAddress(null, 24);
fail("Null InetAddress should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
try {
address = new LinkAddress((String) null, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
fail("Null string should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
try {
address = new LinkAddress((InterfaceAddress) null);
fail("Null string should cause NullPointerException");
} catch(NullPointerException expected) {}
// Invalid prefix lengths are rejected.
try {
address = new LinkAddress(V4_ADDRESS, -1);
fail("Negative IPv4 prefix length should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
try {
address = new LinkAddress(V6_ADDRESS, -1);
fail("Negative IPv6 prefix length should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
try {
address = new LinkAddress(V4_ADDRESS, 33);
fail("/33 IPv4 prefix length should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
try {
address = new LinkAddress(V4 + "/33", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
fail("/33 IPv4 prefix length should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
try {
address = new LinkAddress(V6_ADDRESS, 129, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
fail("/129 IPv6 prefix length should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
try {
address = new LinkAddress(V6 + "/129", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
fail("/129 IPv6 prefix length should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
// Multicast addresses are rejected.
try {
address = new LinkAddress("224.0.0.2/32");
fail("IPv4 multicast address should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
try {
address = new LinkAddress("ff02::1/128");
fail("IPv6 multicast address should cause IllegalArgumentException");
} catch(IllegalArgumentException expected) {}
}
@Test
public void testAddressScopes() {
assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope());
assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope());
assertEquals(RT_SCOPE_LINK, new LinkAddress("::1/128").getScope());
assertEquals(RT_SCOPE_LINK, new LinkAddress("127.0.0.5/8").getScope());
assertEquals(RT_SCOPE_LINK, new LinkAddress("fe80::ace:d00d/64").getScope());
assertEquals(RT_SCOPE_LINK, new LinkAddress("169.254.5.12/16").getScope());
assertEquals(RT_SCOPE_SITE, new LinkAddress("fec0::dead/64").getScope());
assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("10.1.2.3/21").getScope());
assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("192.0.2.1/25").getScope());
assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("2001:db8::/64").getScope());
assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("5000::/127").getScope());
}
private void assertIsSameAddressAs(LinkAddress l1, LinkAddress l2) {
assertTrue(l1 + " unexpectedly does not have same address as " + l2,
l1.isSameAddressAs(l2));
assertTrue(l2 + " unexpectedly does not have same address as " + l1,
l2.isSameAddressAs(l1));
}
private void assertIsNotSameAddressAs(LinkAddress l1, LinkAddress l2) {
assertFalse(l1 + " unexpectedly has same address as " + l2,
l1.isSameAddressAs(l2));
assertFalse(l2 + " unexpectedly has same address as " + l1,
l1.isSameAddressAs(l2));
}
@Test
public void testEqualsAndSameAddressAs() {
LinkAddress l1, l2, l3;
l1 = new LinkAddress("2001:db8::1/64");
l2 = new LinkAddress("2001:db8::1/64");
assertEqualBothWays(l1, l2);
assertIsSameAddressAs(l1, l2);
l2 = new LinkAddress("2001:db8::1/65");
assertNotEqualEitherWay(l1, l2);
assertIsNotSameAddressAs(l1, l2);
l2 = new LinkAddress("2001:db8::2/64");
assertNotEqualEitherWay(l1, l2);
assertIsNotSameAddressAs(l1, l2);
l1 = new LinkAddress("192.0.2.1/24");
l2 = new LinkAddress("192.0.2.1/24");
assertEqualBothWays(l1, l2);
assertIsSameAddressAs(l1, l2);
l2 = new LinkAddress("192.0.2.1/23");
assertNotEqualEitherWay(l1, l2);
assertIsNotSameAddressAs(l1, l2);
l2 = new LinkAddress("192.0.2.2/24");
assertNotEqualEitherWay(l1, l2);
assertIsNotSameAddressAs(l1, l2);
// Check equals() and isSameAddressAs() on identical addresses with different flags.
l1 = new LinkAddress(V6_ADDRESS, 64);
l2 = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
assertEqualBothWays(l1, l2);
assertIsSameAddressAs(l1, l2);
l2 = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_UNIVERSE);
assertNotEqualEitherWay(l1, l2);
assertIsSameAddressAs(l1, l2);
// Check equals() and isSameAddressAs() on identical addresses with different scope.
l1 = new LinkAddress(V4_ADDRESS, 24);
l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_UNIVERSE);
assertEqualBothWays(l1, l2);
assertIsSameAddressAs(l1, l2);
l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_HOST);
assertNotEqualEitherWay(l1, l2);
assertIsSameAddressAs(l1, l2);
// Addresses with the same start or end bytes aren't equal between families.
l1 = new LinkAddress("32.1.13.184/24");
l2 = new LinkAddress("2001:db8::1/24");
l3 = new LinkAddress("::2001:db8/24");
byte[] ipv4Bytes = l1.getAddress().getAddress();
byte[] l2FirstIPv6Bytes = Arrays.copyOf(l2.getAddress().getAddress(), 4);
byte[] l3LastIPv6Bytes = Arrays.copyOfRange(l3.getAddress().getAddress(), 12, 16);
assertTrue(Arrays.equals(ipv4Bytes, l2FirstIPv6Bytes));
assertTrue(Arrays.equals(ipv4Bytes, l3LastIPv6Bytes));
assertNotEqualEitherWay(l1, l2);
assertIsNotSameAddressAs(l1, l2);
assertNotEqualEitherWay(l1, l3);
assertIsNotSameAddressAs(l1, l3);
// Because we use InetAddress, an IPv4 address is equal to its IPv4-mapped address.
// TODO: Investigate fixing this.
String addressString = V4 + "/24";
l1 = new LinkAddress(addressString);
l2 = new LinkAddress("::ffff:" + addressString);
assertEqualBothWays(l1, l2);
assertIsSameAddressAs(l1, l2);
}
@Test
public void testHashCode() {
LinkAddress l1, l2;
l1 = new LinkAddress(V4_ADDRESS, 23);
l2 = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
assertNotEquals(l1.hashCode(), l2.hashCode());
l1 = new LinkAddress(V6_ADDRESS, 128);
l2 = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
assertNotEquals(l1.hashCode(), l2.hashCode());
}
@Test
public void testParceling() {
LinkAddress l;
l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
assertParcelingIsLossless(l);
l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
assertParcelingIsLossless(l);
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testLifetimeParceling() {
final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, 456, 1L, 3600000L);
assertParcelingIsLossless(l);
}
@Test @IgnoreAfter(Build.VERSION_CODES.Q)
public void testFieldCount_Q() {
assertFieldCountEquals(4, LinkAddress.class);
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testFieldCount() {
// Make sure any new field is covered by the above parceling tests when changing this number
assertFieldCountEquals(6, LinkAddress.class);
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testDeprecationTime() {
try {
new LinkAddress(V6_ADDRESS, 64, 0, 456,
LinkAddress.LIFETIME_UNKNOWN, 100000L);
fail("Only one time provided should cause exception");
} catch (IllegalArgumentException expected) { }
try {
new LinkAddress(V6_ADDRESS, 64, 0, 456,
200000L, 100000L);
fail("deprecation time later than expiration time should cause exception");
} catch (IllegalArgumentException expected) { }
try {
new LinkAddress(V6_ADDRESS, 64, 0, 456,
-2, 100000L);
fail("negative deprecation time should cause exception");
} catch (IllegalArgumentException expected) { }
LinkAddress addr = new LinkAddress(V6_ADDRESS, 64, 0, 456, 100000L, 200000L);
assertEquals(100000L, addr.getDeprecationTime());
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testExpirationTime() {
try {
new LinkAddress(V6_ADDRESS, 64, 0, 456,
200000L, LinkAddress.LIFETIME_UNKNOWN);
fail("Only one time provided should cause exception");
} catch (IllegalArgumentException expected) { }
try {
new LinkAddress(V6_ADDRESS, 64, 0, 456,
100000L, -2);
fail("negative expiration time should cause exception");
} catch (IllegalArgumentException expected) { }
LinkAddress addr = new LinkAddress(V6_ADDRESS, 64, 0, 456, 100000L, 200000L);
assertEquals(200000L, addr.getExpirationTime());
}
@Test
public void testGetFlags() {
LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, RT_SCOPE_HOST);
assertEquals(123, l.getFlags());
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testGetFlags_Deprecation() {
// Test if deprecated bit was added/remove automatically based on the provided deprecation
// time
LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
1L, LinkAddress.LIFETIME_PERMANENT);
// Check if the flag is added automatically.
assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
SystemClock.elapsedRealtime() + 100000L, LinkAddress.LIFETIME_PERMANENT);
// Check if the flag is removed automatically.
assertTrue((l.getFlags() & IFA_F_DEPRECATED) == 0);
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
LinkAddress.LIFETIME_PERMANENT, LinkAddress.LIFETIME_PERMANENT);
// Check if the permanent flag is added.
assertTrue((l.getFlags() & IFA_F_PERMANENT) != 0);
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_HOST,
1000L, SystemClock.elapsedRealtime() + 100000L);
// Check if the permanent flag is removed
assertTrue((l.getFlags() & IFA_F_PERMANENT) == 0);
}
private void assertGlobalPreferred(LinkAddress l, String msg) {
assertTrue(msg, l.isGlobalPreferred());
}
private void assertNotGlobalPreferred(LinkAddress l, String msg) {
assertFalse(msg, l.isGlobalPreferred());
}
@Test
public void testIsGlobalPreferred() {
LinkAddress l;
l = new LinkAddress(V4_ADDRESS, 32, 0, RT_SCOPE_UNIVERSE);
assertGlobalPreferred(l, "v4,global,noflags");
l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_UNIVERSE);
assertGlobalPreferred(l, "v4-rfc1918,global,noflags");
l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_SITE);
assertNotGlobalPreferred(l, "v4-rfc1918,site-local,noflags");
l = new LinkAddress("127.0.0.7/8", 0, RT_SCOPE_HOST);
assertNotGlobalPreferred(l, "v4-localhost,node-local,noflags");
l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
assertGlobalPreferred(l, "v6,global,noflags");
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
assertGlobalPreferred(l, "v6,global,permanent");
// IPv6 ULAs are not acceptable "global preferred" addresses.
l = new LinkAddress("fc12::1/64", 0, RT_SCOPE_UNIVERSE);
assertNotGlobalPreferred(l, "v6,ula1,noflags");
l = new LinkAddress("fd34::1/64", 0, RT_SCOPE_UNIVERSE);
assertNotGlobalPreferred(l, "v6,ula2,noflags");
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_UNIVERSE);
assertGlobalPreferred(l, "v6,global,tempaddr");
l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DADFAILED),
RT_SCOPE_UNIVERSE);
assertNotGlobalPreferred(l, "v6,global,tempaddr+dadfailed");
l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DEPRECATED),
RT_SCOPE_UNIVERSE);
assertNotGlobalPreferred(l, "v6,global,tempaddr+deprecated");
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_SITE);
assertNotGlobalPreferred(l, "v6,site-local,tempaddr");
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_LINK);
assertNotGlobalPreferred(l, "v6,link-local,tempaddr");
l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_HOST);
assertNotGlobalPreferred(l, "v6,node-local,tempaddr");
l = new LinkAddress("::1/128", IFA_F_PERMANENT, RT_SCOPE_HOST);
assertNotGlobalPreferred(l, "v6-localhost,node-local,permanent");
l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_TENTATIVE),
RT_SCOPE_UNIVERSE);
assertNotGlobalPreferred(l, "v6,global,tempaddr+tentative");
l = new LinkAddress(V6_ADDRESS, 64,
(IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
RT_SCOPE_UNIVERSE);
assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testIsGlobalPreferred_DeprecatedInFuture() {
final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
RT_SCOPE_UNIVERSE, SystemClock.elapsedRealtime() + 100000,
SystemClock.elapsedRealtime() + 200000);
// Although the deprecated bit is set, but the deprecation time is in the future, test
// if the flag is removed automatically.
assertGlobalPreferred(l, "v6,global,tempaddr+deprecated in the future");
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2020 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 android.net
import android.net.wifi.aware.DiscoverySession
import android.net.wifi.aware.PeerHandle
import android.net.wifi.aware.WifiAwareNetworkSpecifier
import android.os.Build
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import java.lang.IllegalStateException
import org.junit.Assert.assertFalse
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
@RunWith(AndroidJUnit4::class)
@SmallTest
class MatchAllNetworkSpecifierTest {
@Rule @JvmField
val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
private val specifier = MatchAllNetworkSpecifier()
private val discoverySession = Mockito.mock(DiscoverySession::class.java)
private val peerHandle = Mockito.mock(PeerHandle::class.java)
private val wifiAwareNetworkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession,
peerHandle).build()
@Test
fun testParcel() {
assertParcelSane(MatchAllNetworkSpecifier(), 0)
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.Q)
@IgnoreAfter(Build.VERSION_CODES.R)
// Only run this test on Android R.
// The method - satisfiedBy() has changed to canBeSatisfiedBy() starting from Android R, so the
// method - canBeSatisfiedBy() cannot be found when running this test on Android Q.
fun testCanBeSatisfiedBy_OnlyForR() {
// MatchAllNetworkSpecifier didn't follow its parent class to change the satisfiedBy() to
// canBeSatisfiedBy(), so if a caller calls MatchAllNetworkSpecifier#canBeSatisfiedBy(), the
// NetworkSpecifier#canBeSatisfiedBy() will be called actually, and false will be returned.
// Although it's not meeting the expectation, the behavior still needs to be verified.
assertFalse(specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier))
}
@Test(expected = IllegalStateException::class)
@IgnoreUpTo(Build.VERSION_CODES.R)
fun testCanBeSatisfiedBy() {
specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier)
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2020 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 android.net
import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS
import android.net.InvalidPacketException.ERROR_INVALID_PORT
import android.net.NattSocketKeepalive.NATT_PORT
import android.os.Build
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertEqualBothWays
import com.android.testutils.assertFieldCountEquals
import com.android.testutils.assertParcelSane
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.parcelingRoundTrip
import java.net.InetAddress
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Assert.fail
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SmallTest
class NattKeepalivePacketDataTest {
@Rule @JvmField
val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
/* Refer to the definition in {@code NattKeepalivePacketData} */
private val IPV4_HEADER_LENGTH = 20
private val UDP_HEADER_LENGTH = 8
private val TEST_PORT = 4243
private val TEST_PORT2 = 4244
private val TEST_SRC_ADDRV4 = "198.168.0.2".address()
private val TEST_DST_ADDRV4 = "198.168.0.1".address()
private val TEST_ADDRV6 = "2001:db8::1".address()
private fun String.address() = InetAddresses.parseNumericAddress(this)
private fun nattKeepalivePacket(
srcAddress: InetAddress? = TEST_SRC_ADDRV4,
srcPort: Int = TEST_PORT,
dstAddress: InetAddress? = TEST_DST_ADDRV4,
dstPort: Int = NATT_PORT
) = NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort, dstAddress, dstPort)
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
fun testConstructor() {
try {
nattKeepalivePacket(dstPort = TEST_PORT)
fail("Dst port is not NATT port should cause exception")
} catch (e: InvalidPacketException) {
assertEquals(e.error, ERROR_INVALID_PORT)
}
try {
nattKeepalivePacket(srcAddress = TEST_ADDRV6)
fail("A v6 srcAddress should cause exception")
} catch (e: InvalidPacketException) {
assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
}
try {
nattKeepalivePacket(dstAddress = TEST_ADDRV6)
fail("A v6 dstAddress should cause exception")
} catch (e: InvalidPacketException) {
assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
}
try {
parcelingRoundTrip(
NattKeepalivePacketData(TEST_SRC_ADDRV4, TEST_PORT, TEST_DST_ADDRV4, TEST_PORT,
byteArrayOf(12, 31, 22, 44)))
fail("Invalid data should cause exception")
} catch (e: IllegalArgumentException) { }
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
fun testParcel() {
assertParcelSane(nattKeepalivePacket(), 0)
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
fun testEquals() {
assertEqualBothWays(nattKeepalivePacket(), nattKeepalivePacket())
assertNotEquals(nattKeepalivePacket(dstAddress = TEST_SRC_ADDRV4), nattKeepalivePacket())
assertNotEquals(nattKeepalivePacket(srcAddress = TEST_DST_ADDRV4), nattKeepalivePacket())
// Test src port only because dst port have to be NATT_PORT
assertNotEquals(nattKeepalivePacket(srcPort = TEST_PORT2), nattKeepalivePacket())
// Make sure the parceling test is updated if fields are added in the base class.
assertFieldCountEquals(5, KeepalivePacketData::class.java)
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
fun testHashCode() {
assertEquals(nattKeepalivePacket().hashCode(), nattKeepalivePacket().hashCode())
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2019 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 android.net
import android.os.Build
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.modules.utils.build.SdkLevel.isAtLeastS
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.assertParcelSane
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SmallTest
class NetworkAgentConfigTest {
@Rule @JvmField
val ignoreRule = DevSdkIgnoreRule()
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
fun testParcelNetworkAgentConfig() {
val config = NetworkAgentConfig.Builder().apply {
setExplicitlySelected(true)
setLegacyType(ConnectivityManager.TYPE_ETHERNET)
setSubscriberId("MySubId")
setPartialConnectivityAcceptable(false)
setUnvalidatedConnectivityAcceptable(true)
if (isAtLeastS()) {
setBypassableVpn(true)
}
}.build()
if (isAtLeastS()) {
// From S, the config will have 12 items
assertParcelSane(config, 12)
} else {
// For R or below, the config will have 10 items
assertParcelSane(config, 10)
}
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
fun testBuilder() {
val config = NetworkAgentConfig.Builder().apply {
setExplicitlySelected(true)
setLegacyType(ConnectivityManager.TYPE_ETHERNET)
setSubscriberId("MySubId")
setPartialConnectivityAcceptable(false)
setUnvalidatedConnectivityAcceptable(true)
setLegacyTypeName("TEST_NETWORK")
if (isAtLeastS()) {
setNat64DetectionEnabled(false)
setProvisioningNotificationEnabled(false)
setBypassableVpn(true)
}
}.build()
assertTrue(config.isExplicitlySelected())
assertEquals(ConnectivityManager.TYPE_ETHERNET, config.getLegacyType())
assertEquals("MySubId", config.getSubscriberId())
assertFalse(config.isPartialConnectivityAcceptable())
assertTrue(config.isUnvalidatedConnectivityAcceptable())
assertEquals("TEST_NETWORK", config.getLegacyTypeName())
if (isAtLeastS()) {
assertFalse(config.isNat64DetectionEnabled())
assertFalse(config.isProvisioningNotificationEnabled())
assertTrue(config.isBypassableVpn())
} else {
assertTrue(config.isNat64DetectionEnabled())
assertTrue(config.isProvisioningNotificationEnabled())
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,201 @@
/*
* Copyright (C) 2020 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 android.net
import android.app.Instrumentation
import android.content.Context
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequested
import android.os.Build
import android.os.HandlerThread
import android.os.Looper
import androidx.test.InstrumentationRegistry
import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.CompatUtil
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.isDevSdkInRange
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.verifyNoMoreInteractions
import java.util.UUID
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
private const val DEFAULT_TIMEOUT_MS = 5000L
private val instrumentation: Instrumentation
get() = InstrumentationRegistry.getInstrumentation()
private val context: Context get() = InstrumentationRegistry.getContext()
private val PROVIDER_NAME = "NetworkProviderTest"
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.Q)
class NetworkProviderTest {
private val mCm = context.getSystemService(ConnectivityManager::class.java)
private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread")
@Before
fun setUp() {
instrumentation.getUiAutomation().adoptShellPermissionIdentity()
mHandlerThread.start()
}
@After
fun tearDown() {
mHandlerThread.quitSafely()
instrumentation.getUiAutomation().dropShellPermissionIdentity()
}
private class TestNetworkProvider(context: Context, looper: Looper) :
NetworkProvider(context, looper, PROVIDER_NAME) {
private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
sealed class CallbackEntry {
data class OnNetworkRequested(
val request: NetworkRequest,
val score: Int,
val id: Int
) : CallbackEntry()
data class OnNetworkRequestWithdrawn(val request: NetworkRequest) : CallbackEntry()
}
override fun onNetworkRequested(request: NetworkRequest, score: Int, id: Int) {
seenEvents.add(OnNetworkRequested(request, score, id))
}
override fun onNetworkRequestWithdrawn(request: NetworkRequest) {
seenEvents.add(OnNetworkRequestWithdrawn(request))
}
inline fun <reified T : CallbackEntry> expectCallback(
crossinline predicate: (T) -> Boolean
) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
}
private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider {
return TestNetworkProvider(ctx, mHandlerThread.looper)
}
@Test
fun testOnNetworkRequested() {
val provider = createNetworkProvider()
assertEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
mCm.registerNetworkProvider(provider)
assertNotEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
val specifier = CompatUtil.makeTestNetworkSpecifier(
UUID.randomUUID().toString())
val nr: NetworkRequest = NetworkRequest.Builder()
.addTransportType(TRANSPORT_TEST)
.setNetworkSpecifier(specifier)
.build()
val cb = ConnectivityManager.NetworkCallback()
mCm.requestNetwork(nr, cb)
provider.expectCallback<OnNetworkRequested>() { callback ->
callback.request.getNetworkSpecifier() == specifier &&
callback.request.hasTransport(TRANSPORT_TEST)
}
val initialScore = 40
val updatedScore = 60
val nc = NetworkCapabilities().apply {
addTransportType(NetworkCapabilities.TRANSPORT_TEST)
removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
setNetworkSpecifier(specifier)
}
val lp = LinkProperties()
val config = NetworkAgentConfig.Builder().build()
val agent = object : NetworkAgent(context, mHandlerThread.looper, "TestAgent", nc, lp,
initialScore, config, provider) {}
provider.expectCallback<OnNetworkRequested>() { callback ->
callback.request.getNetworkSpecifier() == specifier &&
callback.score == initialScore &&
callback.id == agent.providerId
}
agent.sendNetworkScore(updatedScore)
provider.expectCallback<OnNetworkRequested>() { callback ->
callback.request.getNetworkSpecifier() == specifier &&
callback.score == updatedScore &&
callback.id == agent.providerId
}
mCm.unregisterNetworkCallback(cb)
provider.expectCallback<OnNetworkRequestWithdrawn>() { callback ->
callback.request.getNetworkSpecifier() == specifier &&
callback.request.hasTransport(TRANSPORT_TEST)
}
mCm.unregisterNetworkProvider(provider)
// Provider id should be ID_NONE after unregister network provider
assertEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
// unregisterNetworkProvider should not crash even if it's called on an
// already unregistered provider.
mCm.unregisterNetworkProvider(provider)
}
private class TestNetworkCallback : ConnectivityManager.NetworkCallback() {
private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
sealed class CallbackEntry {
object OnUnavailable : CallbackEntry()
}
override fun onUnavailable() {
seenEvents.add(OnUnavailable)
}
inline fun <reified T : CallbackEntry> expectCallback(
crossinline predicate: (T) -> Boolean
) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
}
@Test
fun testDeclareNetworkRequestUnfulfillable() {
val mockContext = mock(Context::class.java)
doReturn(mCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE)
val provider = createNetworkProvider(mockContext)
// ConnectivityManager not required at creation time after R
if (!isDevSdkInRange(0, Build.VERSION_CODES.R)) {
verifyNoMoreInteractions(mockContext)
}
mCm.registerNetworkProvider(provider)
val specifier = CompatUtil.makeTestNetworkSpecifier(
UUID.randomUUID().toString())
val nr: NetworkRequest = NetworkRequest.Builder()
.addTransportType(TRANSPORT_TEST)
.setNetworkSpecifier(specifier)
.build()
val cb = TestNetworkCallback()
mCm.requestNetwork(nr, cb)
provider.declareNetworkRequestUnfulfillable(nr)
cb.expectCallback<OnUnavailable>() { nr.getNetworkSpecifier() == specifier }
mCm.unregisterNetworkProvider(provider)
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2020 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 android.net
import android.os.Build
import androidx.test.filters.SmallTest
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import kotlin.test.assertTrue
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotEquals
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.Q)
class NetworkSpecifierTest {
private class TestNetworkSpecifier(
val intData: Int = 123,
val stringData: String = "init"
) : NetworkSpecifier() {
override fun canBeSatisfiedBy(other: NetworkSpecifier?): Boolean =
other != null &&
other is TestNetworkSpecifier &&
other.intData >= intData &&
stringData.equals(other.stringData)
override fun redact(): NetworkSpecifier = TestNetworkSpecifier(intData, "redact")
}
@Test
fun testRedact() {
val ns: TestNetworkSpecifier = TestNetworkSpecifier()
val redactNs = ns.redact()
assertTrue(redactNs is TestNetworkSpecifier)
assertEquals(ns.intData, redactNs.intData)
assertNotEquals(ns.stringData, redactNs.stringData)
assertTrue("redact".equals(redactNs.stringData))
}
@Test
fun testcanBeSatisfiedBy() {
val target: TestNetworkSpecifier = TestNetworkSpecifier()
assertFalse(target.canBeSatisfiedBy(null))
assertTrue(target.canBeSatisfiedBy(TestNetworkSpecifier()))
val otherNs = TelephonyNetworkSpecifier.Builder().setSubscriptionId(123).build()
assertFalse(target.canBeSatisfiedBy(otherNs))
assertTrue(target.canBeSatisfiedBy(TestNetworkSpecifier(intData = 999)))
assertFalse(target.canBeSatisfiedBy(TestNetworkSpecifier(intData = 1)))
assertFalse(target.canBeSatisfiedBy(TestNetworkSpecifier(stringData = "diff")))
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2019 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 android.net;
import static org.junit.Assert.assertEquals;
import android.os.Build;
import android.os.IBinder;
import androidx.test.runner.AndroidJUnit4;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class NetworkStackTest {
@Rule
public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
@Mock private IBinder mConnectorBinder;
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testGetService() {
NetworkStack.setServiceForTest(mConnectorBinder);
assertEquals(NetworkStack.getService(), mConnectorBinder);
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2021 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 android.net
import android.net.ConnectivityManager.TYPE_NONE
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.InetAddresses.parseNumericAddress
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.os.Build
import androidx.test.filters.SmallTest
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.assertParcelSane
import org.junit.Test
import org.junit.runner.RunWith
import java.net.Inet4Address
import java.net.Inet6Address
private const val TEST_IMSI = "imsi1"
private const val TEST_SSID = "SSID1"
private const val TEST_NETID = 123
private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address
private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address
private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24")
private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64")
private val TEST_IFACE = "fake0"
private val TEST_LINK_PROPERTIES = LinkProperties().apply {
interfaceName = TEST_IFACE
addLinkAddress(TEST_IPV4_LINKADDR)
addLinkAddress(TEST_IPV6_LINKADDR)
// Add default routes
addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_GATEWAY))
}
private val TEST_CAPABILITIES = NetworkCapabilities().apply {
addTransportType(TRANSPORT_WIFI)
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
setSSID(TEST_SSID)
}
@SmallTest
@RunWith(DevSdkIgnoreRunner::class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
class NetworkStateSnapshotTest {
@Test
fun testParcelUnparcel() {
val emptySnapshot = NetworkStateSnapshot(Network(TEST_NETID), NetworkCapabilities(),
LinkProperties(), null, TYPE_NONE)
val snapshot = NetworkStateSnapshot(
Network(TEST_NETID), TEST_CAPABILITIES, TEST_LINK_PROPERTIES, TEST_IMSI, TYPE_WIFI)
assertParcelSane(emptySnapshot, 5)
assertParcelSane(snapshot, 5)
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (C) 2015 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 android.net;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.platform.test.annotations.AppModeFull;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.net.DatagramSocket;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.SocketException;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkTest {
final Network mNetwork = new Network(99);
@Test
public void testBindSocketOfInvalidFdThrows() throws Exception {
final FileDescriptor fd = new FileDescriptor();
assertFalse(fd.valid());
try {
mNetwork.bindSocket(fd);
fail("SocketException not thrown");
} catch (SocketException expected) {}
}
@Test
public void testBindSocketOfNonSocketFdThrows() throws Exception {
final File devNull = new File("/dev/null");
assertTrue(devNull.canRead());
final FileInputStream fis = new FileInputStream(devNull);
assertTrue(null != fis.getFD());
assertTrue(fis.getFD().valid());
try {
mNetwork.bindSocket(fis.getFD());
fail("SocketException not thrown");
} catch (SocketException expected) {}
}
@Test
@AppModeFull(reason = "Socket cannot bind in instant app mode")
public void testBindSocketOfConnectedDatagramSocketThrows() throws Exception {
final DatagramSocket mDgramSocket = new DatagramSocket(0, (InetAddress) Inet6Address.ANY);
mDgramSocket.connect((InetAddress) Inet6Address.LOOPBACK, 53);
assertTrue(mDgramSocket.isConnected());
try {
mNetwork.bindSocket(mDgramSocket);
fail("SocketException not thrown");
} catch (SocketException expected) {}
}
@Test
public void testBindSocketOfLocalSocketThrows() throws Exception {
final LocalSocket mLocalClient = new LocalSocket();
mLocalClient.bind(new LocalSocketAddress("testClient"));
assertTrue(mLocalClient.getFileDescriptor().valid());
try {
mNetwork.bindSocket(mLocalClient.getFileDescriptor());
fail("SocketException not thrown");
} catch (SocketException expected) {}
final LocalServerSocket mLocalServer = new LocalServerSocket("testServer");
mLocalClient.connect(mLocalServer.getLocalSocketAddress());
assertTrue(mLocalClient.isConnected());
try {
mNetwork.bindSocket(mLocalClient.getFileDescriptor());
fail("SocketException not thrown");
} catch (SocketException expected) {}
}
@Test
public void testZeroIsObviousForDebugging() {
Network zero = new Network(0);
assertEquals(0, zero.hashCode());
assertEquals(0, zero.getNetworkHandle());
assertEquals("0", zero.toString());
}
@Test
public void testGetNetworkHandle() {
Network one = new Network(1);
Network two = new Network(2);
Network three = new Network(3);
// None of the hashcodes are zero.
assertNotEquals(0, one.hashCode());
assertNotEquals(0, two.hashCode());
assertNotEquals(0, three.hashCode());
// All the hashcodes are distinct.
assertNotEquals(one.hashCode(), two.hashCode());
assertNotEquals(one.hashCode(), three.hashCode());
assertNotEquals(two.hashCode(), three.hashCode());
// None of the handles are zero.
assertNotEquals(0, one.getNetworkHandle());
assertNotEquals(0, two.getNetworkHandle());
assertNotEquals(0, three.getNetworkHandle());
// All the handles are distinct.
assertNotEquals(one.getNetworkHandle(), two.getNetworkHandle());
assertNotEquals(one.getNetworkHandle(), three.getNetworkHandle());
assertNotEquals(two.getNetworkHandle(), three.getNetworkHandle());
// The handles are not equal to the hashcodes.
assertNotEquals(one.hashCode(), one.getNetworkHandle());
assertNotEquals(two.hashCode(), two.getNetworkHandle());
assertNotEquals(three.hashCode(), three.getNetworkHandle());
// Adjust as necessary to test an implementation's specific constants.
// When running with runtest, "adb logcat -s TestRunner" can be useful.
assertEquals(7700664333L, one.getNetworkHandle());
assertEquals(11995631629L, two.getNetworkHandle());
assertEquals(16290598925L, three.getNetworkHandle());
}
@Test
public void testGetPrivateDnsBypassingCopy() {
final Network copy = mNetwork.getPrivateDnsBypassingCopy();
assertEquals(mNetwork.netId, copy.netId);
assertNotEquals(copy.netId, copy.getNetIdForResolv());
assertNotEquals(mNetwork.getNetIdForResolv(), copy.getNetIdForResolv());
}
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2021 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 android.net;
import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.os.Build;
import androidx.test.filters.SmallTest;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Map;
@IgnoreUpTo(Build.VERSION_CODES.R)
@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
public class OemNetworkPreferencesTest {
private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
private static final String TEST_PACKAGE = "com.google.apps.contacts";
private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder();
@Test
public void testBuilderAddNetworkPreferenceRequiresNonNullPackageName() {
assertThrows(NullPointerException.class,
() -> mBuilder.addNetworkPreference(null, TEST_PREF));
}
@Test
public void testBuilderRemoveNetworkPreferenceRequiresNonNullPackageName() {
assertThrows(NullPointerException.class,
() -> mBuilder.clearNetworkPreference(null));
}
@Test
public void testGetNetworkPreferenceReturnsCorrectValue() {
final int expectedNumberOfMappings = 1;
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
final Map<String, Integer> networkPreferences =
mBuilder.build().getNetworkPreferences();
assertEquals(expectedNumberOfMappings, networkPreferences.size());
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
}
@Test
public void testGetNetworkPreferenceReturnsUnmodifiableValue() {
final String newPackage = "new.com.google.apps.contacts";
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
final Map<String, Integer> networkPreferences =
mBuilder.build().getNetworkPreferences();
assertThrows(UnsupportedOperationException.class,
() -> networkPreferences.put(newPackage, TEST_PREF));
assertThrows(UnsupportedOperationException.class,
() -> networkPreferences.remove(TEST_PACKAGE));
}
@Test
public void testToStringReturnsCorrectValue() {
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
final String networkPreferencesString = mBuilder.build().getNetworkPreferences().toString();
assertTrue(networkPreferencesString.contains(Integer.toString(TEST_PREF)));
assertTrue(networkPreferencesString.contains(TEST_PACKAGE));
}
@Test
public void testOemNetworkPreferencesParcelable() {
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
final OemNetworkPreferences prefs = mBuilder.build();
assertParcelSane(prefs, 1 /* fieldCount */);
}
@Test
public void testAddNetworkPreferenceOverwritesPriorPreference() {
final int newPref = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
Map<String, Integer> networkPreferences =
mBuilder.build().getNetworkPreferences();
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), TEST_PREF);
mBuilder.addNetworkPreference(TEST_PACKAGE, newPref);
networkPreferences = mBuilder.build().getNetworkPreferences();
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), newPref);
}
@Test
public void testRemoveNetworkPreferenceRemovesValue() {
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
Map<String, Integer> networkPreferences =
mBuilder.build().getNetworkPreferences();
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
mBuilder.clearNetworkPreference(TEST_PACKAGE);
networkPreferences = mBuilder.build().getNetworkPreferences();
assertFalse(networkPreferences.containsKey(TEST_PACKAGE));
}
@Test
public void testConstructorByOemNetworkPreferencesSetsValue() {
mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
OemNetworkPreferences networkPreference = mBuilder.build();
final Map<String, Integer> networkPreferences =
new OemNetworkPreferences
.Builder(networkPreference)
.build()
.getNetworkPreferences();
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), TEST_PREF);
}
}

View File

@@ -0,0 +1,434 @@
/*
* Copyright (C) 2010 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 android.net;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static com.android.testutils.MiscAsserts.assertEqualBothWays;
import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.os.Build;
import androidx.core.os.BuildCompat;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class RouteInfoTest {
@Rule
public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
private static final int INVALID_ROUTE_TYPE = -1;
private InetAddress Address(String addr) {
return InetAddresses.parseNumericAddress(addr);
}
private IpPrefix Prefix(String prefix) {
return new IpPrefix(prefix);
}
private static boolean isAtLeastR() {
// BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
}
@Test
public void testConstructor() {
RouteInfo r;
// Invalid input.
try {
r = new RouteInfo((IpPrefix) null, null, "rmnet0");
fail("Expected RuntimeException: destination and gateway null");
} catch (RuntimeException e) { }
try {
r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "rmnet0",
INVALID_ROUTE_TYPE);
fail("Invalid route type should cause exception");
} catch (IllegalArgumentException e) { }
try {
r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("192.0.2.1"), "rmnet0",
RTN_UNREACHABLE);
fail("Address family mismatch should cause exception");
} catch (IllegalArgumentException e) { }
try {
r = new RouteInfo(Prefix("0.0.0.0/0"), Address("2001:db8::1"), "rmnet0",
RTN_UNREACHABLE);
fail("Address family mismatch should cause exception");
} catch (IllegalArgumentException e) { }
// Null destination is default route.
r = new RouteInfo((IpPrefix) null, Address("2001:db8::1"), null);
assertEquals(Prefix("::/0"), r.getDestination());
assertEquals(Address("2001:db8::1"), r.getGateway());
assertNull(r.getInterface());
r = new RouteInfo((IpPrefix) null, Address("192.0.2.1"), "wlan0");
assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
assertEquals(Address("192.0.2.1"), r.getGateway());
assertEquals("wlan0", r.getInterface());
// Null gateway sets gateway to unspecified address (why?).
r = new RouteInfo(Prefix("2001:db8:beef:cafe::/48"), null, "lo");
assertEquals(Prefix("2001:db8:beef::/48"), r.getDestination());
assertEquals(Address("::"), r.getGateway());
assertEquals("lo", r.getInterface());
r = new RouteInfo(Prefix("192.0.2.5/24"), null);
assertEquals(Prefix("192.0.2.0/24"), r.getDestination());
assertEquals(Address("0.0.0.0"), r.getGateway());
assertNull(r.getInterface());
}
@Test
public void testMatches() {
class PatchedRouteInfo {
private final RouteInfo mRouteInfo;
public PatchedRouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
mRouteInfo = new RouteInfo(destination, gateway, iface);
}
public boolean matches(InetAddress destination) {
return mRouteInfo.matches(destination);
}
}
PatchedRouteInfo r;
r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0");
assertTrue(r.matches(Address("2001:db8:f00::ace:d00c")));
assertTrue(r.matches(Address("2001:db8:f00::ace:d00d")));
assertFalse(r.matches(Address("2001:db8:f00::ace:d00e")));
assertFalse(r.matches(Address("2001:db8:f00::bad:d00d")));
assertFalse(r.matches(Address("2001:4868:4860::8888")));
assertFalse(r.matches(Address("8.8.8.8")));
r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0");
assertTrue(r.matches(Address("192.0.2.43")));
assertTrue(r.matches(Address("192.0.3.21")));
assertFalse(r.matches(Address("192.0.0.21")));
assertFalse(r.matches(Address("8.8.8.8")));
PatchedRouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
assertTrue(ipv6Default.matches(Address("2001:db8::f00")));
assertFalse(ipv6Default.matches(Address("192.0.2.1")));
PatchedRouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
assertTrue(ipv4Default.matches(Address("255.255.255.255")));
assertTrue(ipv4Default.matches(Address("192.0.2.1")));
assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
}
@Test
public void testEquals() {
// IPv4
RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
RouteInfo r2 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
assertEqualBothWays(r1, r2);
RouteInfo r3 = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "wlan0");
RouteInfo r4 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::2"), "wlan0");
RouteInfo r5 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "rmnet0");
assertNotEqualEitherWay(r1, r3);
assertNotEqualEitherWay(r1, r4);
assertNotEqualEitherWay(r1, r5);
// IPv6
r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
assertEqualBothWays(r1, r2);
r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
r4 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.2"), "wlan0");
r5 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "rmnet0");
assertNotEqualEitherWay(r1, r3);
assertNotEqualEitherWay(r1, r4);
assertNotEqualEitherWay(r1, r5);
// Interfaces (but not destinations or gateways) can be null.
r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
assertEqualBothWays(r1, r2);
assertNotEqualEitherWay(r1, r3);
}
@Test
public void testHostAndDefaultRoutes() {
RouteInfo r;
r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
assertFalse(r.isHostRoute());
assertTrue(r.isDefaultRoute());
assertTrue(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
assertFalse(r.isHostRoute());
assertTrue(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertTrue(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE);
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertTrue(r.isIPv4UnreachableDefault());
assertFalse(r.isIPv6UnreachableDefault());
}
r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
if (isAtLeastR()) {
assertFalse(r.isIPv4UnreachableDefault());
assertTrue(r.isIPv6UnreachableDefault());
}
}
@Test
public void testTruncation() {
LinkAddress l;
RouteInfo r;
l = new LinkAddress("192.0.2.5/30");
r = new RouteInfo(l, Address("192.0.2.1"), "wlan0");
assertEquals("192.0.2.4", r.getDestination().getAddress().getHostAddress());
l = new LinkAddress("2001:db8:1:f::5/63");
r = new RouteInfo(l, Address("2001:db8:5::1"), "wlan0");
assertEquals("2001:db8:1:e::", r.getDestination().getAddress().getHostAddress());
}
// Make sure that creating routes to multicast addresses doesn't throw an exception. Even though
// there's nothing we can do with them, we don't want to crash if, e.g., someone calls
// requestRouteToHostAddress("230.0.0.0", MOBILE_HIPRI);
@Test
public void testMulticastRoute() {
RouteInfo r;
r = new RouteInfo(Prefix("230.0.0.0/32"), Address("192.0.2.1"), "wlan0");
r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::1"), "wlan0");
// No exceptions? Good.
}
@Test
public void testParceling() {
RouteInfo r;
r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), null);
assertParcelingIsLossless(r);
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
assertParcelingIsLossless(r);
r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0", RTN_UNREACHABLE);
assertParcelingIsLossless(r);
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testMtuParceling() {
final RouteInfo r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::"), "testiface",
RTN_UNREACHABLE, 1450 /* mtu */);
assertParcelingIsLossless(r);
}
@Test @IgnoreAfter(Build.VERSION_CODES.Q)
public void testFieldCount_Q() {
assertFieldCountEquals(6, RouteInfo.class);
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testFieldCount() {
// Make sure any new field is covered by the above parceling tests when changing this number
assertFieldCountEquals(7, RouteInfo.class);
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testMtu() {
RouteInfo r;
r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0",
RouteInfo.RTN_UNICAST, 1500);
assertEquals(1500, r.getMtu());
r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
assertEquals(0, r.getMtu());
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testRouteKey() {
RouteInfo.RouteKey k1, k2;
// Only prefix, null gateway and null interface
k1 = new RouteInfo(Prefix("2001:db8::/128"), null).getRouteKey();
k2 = new RouteInfo(Prefix("2001:db8::/128"), null).getRouteKey();
assertEquals(k1, k2);
assertEquals(k1.hashCode(), k2.hashCode());
// With prefix, gateway and interface. Type and MTU does not affect RouteKey equality
k1 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0",
RTN_UNREACHABLE, 1450).getRouteKey();
k2 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0",
RouteInfo.RTN_UNICAST, 1400).getRouteKey();
assertEquals(k1, k2);
assertEquals(k1.hashCode(), k2.hashCode());
// Different scope IDs are ignored by the kernel, so we consider them equal here too.
k1 = new RouteInfo(Prefix("2001:db8::/64"), Address("fe80::1%1"), "wlan0").getRouteKey();
k2 = new RouteInfo(Prefix("2001:db8::/64"), Address("fe80::1%2"), "wlan0").getRouteKey();
assertEquals(k1, k2);
assertEquals(k1.hashCode(), k2.hashCode());
// Different prefix
k1 = new RouteInfo(Prefix("192.0.2.0/24"), null).getRouteKey();
k2 = new RouteInfo(Prefix("192.0.3.0/24"), null).getRouteKey();
assertNotEquals(k1, k2);
// Different gateway
k1 = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::1"), null).getRouteKey();
k2 = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::2"), null).getRouteKey();
assertNotEquals(k1, k2);
// Different interface
k1 = new RouteInfo(Prefix("ff02::1/128"), null, "tun0").getRouteKey();
k2 = new RouteInfo(Prefix("ff02::1/128"), null, "tun1").getRouteKey();
assertNotEquals(k1, k2);
}
}

View File

@@ -0,0 +1,269 @@
/*
* Copyright (C) 2014 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 android.net;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class StaticIpConfigurationTest {
private static final String ADDRSTR = "192.0.2.2/25";
private static final LinkAddress ADDR = new LinkAddress(ADDRSTR);
private static final InetAddress GATEWAY = IpAddress("192.0.2.1");
private static final InetAddress OFFLINKGATEWAY = IpAddress("192.0.2.129");
private static final InetAddress DNS1 = IpAddress("8.8.8.8");
private static final InetAddress DNS2 = IpAddress("8.8.4.4");
private static final InetAddress DNS3 = IpAddress("4.2.2.2");
private static final String IFACE = "eth0";
private static final String FAKE_DOMAINS = "google.com";
private static InetAddress IpAddress(String addr) {
return InetAddress.parseNumericAddress(addr);
}
private void checkEmpty(StaticIpConfiguration s) {
assertNull(s.ipAddress);
assertNull(s.gateway);
assertNull(s.domains);
assertEquals(0, s.dnsServers.size());
}
private StaticIpConfiguration makeTestObject() {
StaticIpConfiguration s = new StaticIpConfiguration();
s.ipAddress = ADDR;
s.gateway = GATEWAY;
s.dnsServers.add(DNS1);
s.dnsServers.add(DNS2);
s.dnsServers.add(DNS3);
s.domains = FAKE_DOMAINS;
return s;
}
@Test
public void testConstructor() {
StaticIpConfiguration s = new StaticIpConfiguration();
checkEmpty(s);
}
@Test
public void testCopyAndClear() {
StaticIpConfiguration empty = new StaticIpConfiguration((StaticIpConfiguration) null);
checkEmpty(empty);
StaticIpConfiguration s1 = makeTestObject();
StaticIpConfiguration s2 = new StaticIpConfiguration(s1);
assertEquals(s1, s2);
s2.clear();
assertEquals(empty, s2);
}
@Test
public void testHashCodeAndEquals() {
HashSet<Integer> hashCodes = new HashSet();
hashCodes.add(0);
StaticIpConfiguration s = new StaticIpConfiguration();
// Check that this hash code is nonzero and different from all the ones seen so far.
assertTrue(hashCodes.add(s.hashCode()));
s.ipAddress = ADDR;
assertTrue(hashCodes.add(s.hashCode()));
s.gateway = GATEWAY;
assertTrue(hashCodes.add(s.hashCode()));
s.dnsServers.add(DNS1);
assertTrue(hashCodes.add(s.hashCode()));
s.dnsServers.add(DNS2);
assertTrue(hashCodes.add(s.hashCode()));
s.dnsServers.add(DNS3);
assertTrue(hashCodes.add(s.hashCode()));
s.domains = "example.com";
assertTrue(hashCodes.add(s.hashCode()));
assertFalse(s.equals(null));
assertEquals(s, s);
StaticIpConfiguration s2 = new StaticIpConfiguration(s);
assertEquals(s, s2);
s.ipAddress = new LinkAddress(DNS1, 32);
assertNotEquals(s, s2);
s2 = new StaticIpConfiguration(s);
s.domains = "foo";
assertNotEquals(s, s2);
s2 = new StaticIpConfiguration(s);
s.gateway = DNS2;
assertNotEquals(s, s2);
s2 = new StaticIpConfiguration(s);
s.dnsServers.add(DNS3);
assertNotEquals(s, s2);
}
@Test
public void testToLinkProperties() {
LinkProperties expected = new LinkProperties();
expected.setInterfaceName(IFACE);
StaticIpConfiguration s = new StaticIpConfiguration();
assertEquals(expected, s.toLinkProperties(IFACE));
final RouteInfo connectedRoute = new RouteInfo(new IpPrefix(ADDRSTR), null, IFACE);
s.ipAddress = ADDR;
expected.addLinkAddress(ADDR);
expected.addRoute(connectedRoute);
assertEquals(expected, s.toLinkProperties(IFACE));
s.gateway = GATEWAY;
RouteInfo defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), GATEWAY, IFACE);
expected.addRoute(defaultRoute);
assertEquals(expected, s.toLinkProperties(IFACE));
s.gateway = OFFLINKGATEWAY;
expected.removeRoute(defaultRoute);
defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), OFFLINKGATEWAY, IFACE);
expected.addRoute(defaultRoute);
RouteInfo gatewayRoute = new RouteInfo(new IpPrefix("192.0.2.129/32"), null, IFACE);
expected.addRoute(gatewayRoute);
assertEquals(expected, s.toLinkProperties(IFACE));
s.dnsServers.add(DNS1);
expected.addDnsServer(DNS1);
assertEquals(expected, s.toLinkProperties(IFACE));
s.dnsServers.add(DNS2);
s.dnsServers.add(DNS3);
expected.addDnsServer(DNS2);
expected.addDnsServer(DNS3);
assertEquals(expected, s.toLinkProperties(IFACE));
s.domains = FAKE_DOMAINS;
expected.setDomains(FAKE_DOMAINS);
assertEquals(expected, s.toLinkProperties(IFACE));
s.gateway = null;
expected.removeRoute(defaultRoute);
expected.removeRoute(gatewayRoute);
assertEquals(expected, s.toLinkProperties(IFACE));
// Without knowing the IP address, we don't have a directly-connected route, so we can't
// tell if the gateway is off-link or not and we don't add a host route. This isn't a real
// configuration, but we should at least not crash.
s.gateway = OFFLINKGATEWAY;
s.ipAddress = null;
expected.removeLinkAddress(ADDR);
expected.removeRoute(connectedRoute);
expected.addRoute(defaultRoute);
assertEquals(expected, s.toLinkProperties(IFACE));
}
private StaticIpConfiguration passThroughParcel(StaticIpConfiguration s) {
Parcel p = Parcel.obtain();
StaticIpConfiguration s2 = null;
try {
s.writeToParcel(p, 0);
p.setDataPosition(0);
s2 = StaticIpConfiguration.readFromParcel(p);
} finally {
p.recycle();
}
assertNotNull(s2);
return s2;
}
@Test
public void testParceling() {
StaticIpConfiguration s = makeTestObject();
StaticIpConfiguration s2 = passThroughParcel(s);
assertEquals(s, s2);
}
@Test
public void testBuilder() {
final ArrayList<InetAddress> dnsServers = new ArrayList<>();
dnsServers.add(DNS1);
final StaticIpConfiguration s = new StaticIpConfiguration.Builder()
.setIpAddress(ADDR)
.setGateway(GATEWAY)
.setDomains(FAKE_DOMAINS)
.setDnsServers(dnsServers)
.build();
assertEquals(s.ipAddress, s.getIpAddress());
assertEquals(ADDR, s.getIpAddress());
assertEquals(s.gateway, s.getGateway());
assertEquals(GATEWAY, s.getGateway());
assertEquals(s.domains, s.getDomains());
assertEquals(FAKE_DOMAINS, s.getDomains());
assertTrue(s.dnsServers.equals(s.getDnsServers()));
assertEquals(1, s.getDnsServers().size());
assertEquals(DNS1, s.getDnsServers().get(0));
}
@Test
public void testAddDnsServers() {
final StaticIpConfiguration s = new StaticIpConfiguration((StaticIpConfiguration) null);
checkEmpty(s);
s.addDnsServer(DNS1);
assertEquals(1, s.getDnsServers().size());
assertEquals(DNS1, s.getDnsServers().get(0));
s.addDnsServer(DNS2);
s.addDnsServer(DNS3);
assertEquals(3, s.getDnsServers().size());
assertEquals(DNS2, s.getDnsServers().get(1));
assertEquals(DNS3, s.getDnsServers().get(2));
}
@Test
public void testGetRoutes() {
final StaticIpConfiguration s = makeTestObject();
final List<RouteInfo> routeInfoList = s.getRoutes(IFACE);
assertEquals(2, routeInfoList.size());
assertEquals(new RouteInfo(ADDR, (InetAddress) null, IFACE), routeInfoList.get(0));
assertEquals(new RouteInfo((IpPrefix) null, GATEWAY, IFACE), routeInfoList.get(1));
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2020 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 android.net
import android.net.InetAddresses.parseNumericAddress
import android.os.Build
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.assertFieldCountEquals
import com.android.testutils.assertParcelSane
import org.junit.Test
import org.junit.runner.RunWith
import java.net.InetAddress
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
@RunWith(DevSdkIgnoreRunner::class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) // TcpKeepalivePacketData added to SDK in S
class TcpKeepalivePacketDataTest {
private fun makeData(
srcAddress: InetAddress = parseNumericAddress("192.0.2.123"),
srcPort: Int = 1234,
dstAddress: InetAddress = parseNumericAddress("192.0.2.231"),
dstPort: Int = 4321,
data: ByteArray = byteArrayOf(1, 2, 3),
tcpSeq: Int = 135,
tcpAck: Int = 246,
tcpWnd: Int = 1234,
tcpWndScale: Int = 2,
ipTos: Int = 0x12,
ipTtl: Int = 10
) = TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, data, tcpSeq, tcpAck,
tcpWnd, tcpWndScale, ipTos, ipTtl)
@Test
fun testEquals() {
val data1 = makeData()
val data2 = makeData()
assertEquals(data1, data2)
assertEquals(data1.hashCode(), data2.hashCode())
}
@Test
fun testNotEquals() {
assertNotEquals(makeData(srcAddress = parseNumericAddress("192.0.2.124")), makeData())
assertNotEquals(makeData(srcPort = 1235), makeData())
assertNotEquals(makeData(dstAddress = parseNumericAddress("192.0.2.232")), makeData())
assertNotEquals(makeData(dstPort = 4322), makeData())
// .equals does not test .packet, as it should be generated from the other fields
assertNotEquals(makeData(tcpSeq = 136), makeData())
assertNotEquals(makeData(tcpAck = 247), makeData())
assertNotEquals(makeData(tcpWnd = 1235), makeData())
assertNotEquals(makeData(tcpWndScale = 3), makeData())
assertNotEquals(makeData(ipTos = 0x14), makeData())
assertNotEquals(makeData(ipTtl = 11), makeData())
// Update above assertions if field is added
assertFieldCountEquals(5, KeepalivePacketData::class.java)
assertFieldCountEquals(6, TcpKeepalivePacketData::class.java)
}
@Test
fun testParcelUnparcel() {
assertParcelSane(makeData(), fieldCount = 6) { a, b ->
// .equals() does not verify .packet
a == b && a.packet contentEquals b.packet
}
}
@Test
fun testToString() {
val data = makeData()
val str = data.toString()
assertTrue(str.contains(data.srcAddress.hostAddress))
assertTrue(str.contains(data.srcPort.toString()))
assertTrue(str.contains(data.dstAddress.hostAddress))
assertTrue(str.contains(data.dstPort.toString()))
// .packet not included in toString()
assertTrue(str.contains(data.getTcpSeq().toString()))
assertTrue(str.contains(data.getTcpAck().toString()))
assertTrue(str.contains(data.getTcpWindow().toString()))
assertTrue(str.contains(data.getTcpWindowScale().toString()))
assertTrue(str.contains(data.getIpTos().toString()))
assertTrue(str.contains(data.getIpTtl().toString()))
// Update above assertions if field is added
assertFieldCountEquals(5, KeepalivePacketData::class.java)
assertFieldCountEquals(6, TcpKeepalivePacketData::class.java)
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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 android.net;
import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
import static android.os.UserHandle.SYSTEM;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserHandle.getUid;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.os.Build;
import android.os.UserHandle;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class UidRangeTest {
/*
* UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as
* UidRangeParcel objects.
*/
@Rule
public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
@Test
public void testSingleItemUidRangeAllowed() {
new UidRange(123, 123);
new UidRange(0, 0);
new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
@Test
public void testNegativeUidsDisallowed() {
try {
new UidRange(-2, 100);
fail("Exception not thrown for negative start UID");
} catch (IllegalArgumentException expected) {
}
try {
new UidRange(-200, -100);
fail("Exception not thrown for negative stop UID");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testStopLessThanStartDisallowed() {
final int x = 4195000;
try {
new UidRange(x, x - 1);
fail("Exception not thrown for negative-length UID range");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testGetStartAndEndUser() throws Exception {
final UidRange uidRangeOfPrimaryUser = new UidRange(
getUid(USER_SYSTEM, 10000), getUid(USER_SYSTEM, 10100));
final UidRange uidRangeOfSecondaryUser = new UidRange(
getUid(MIN_SECONDARY_USER_ID, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getStartUser());
assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
final UidRange uidRangeForDifferentUsers = new UidRange(
getUid(USER_SYSTEM, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
}
@Test @IgnoreUpTo(Build.VERSION_CODES.R)
public void testCreateForUser() throws Exception {
final UidRange uidRangeOfPrimaryUser = UidRange.createForUser(SYSTEM);
final UidRange uidRangeOfSecondaryUser = UidRange.createForUser(
UserHandle.of(USER_SYSTEM + 1));
assertTrue(uidRangeOfPrimaryUser.stop < uidRangeOfSecondaryUser.start);
assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getStartUser());
assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getEndUser());
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2021 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 android.net
import android.os.Build
import androidx.test.filters.SmallTest
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.assertParcelSane
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
private const val TEST_OWNER_UID = 123
private const val TEST_IFACE = "test_tun0"
private val TEST_IFACE_LIST = listOf("wlan0", "rmnet_data0", "eth0")
@SmallTest
@RunWith(DevSdkIgnoreRunner::class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
class UnderlyingNetworkInfoTest {
@Test
fun testParcelUnparcel() {
val testInfo = UnderlyingNetworkInfo(TEST_OWNER_UID, TEST_IFACE, TEST_IFACE_LIST)
assertEquals(TEST_OWNER_UID, testInfo.ownerUid)
assertEquals(TEST_IFACE, testInfo.iface)
assertEquals(TEST_IFACE_LIST, testInfo.underlyingIfaces)
assertParcelSane(testInfo, 3)
val emptyInfo = UnderlyingNetworkInfo(0, String(), listOf())
assertEquals(0, emptyInfo.ownerUid)
assertEquals(String(), emptyInfo.iface)
assertEquals(listOf(), emptyInfo.underlyingIfaces)
assertParcelSane(emptyInfo, 3)
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2019 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 android.net.apf;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ApfCapabilitiesTest {
private Context mContext;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getContext();
}
@Test
public void testConstructAndParcel() {
final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
assertEquals(123, caps.apfVersionSupported);
assertEquals(456, caps.maximumApfProgramSize);
assertEquals(789, caps.apfPacketFormat);
assertParcelSane(caps, 3);
}
@Test
public void testEquals() {
assertEquals(new ApfCapabilities(1, 2, 3), new ApfCapabilities(1, 2, 3));
assertNotEquals(new ApfCapabilities(2, 2, 3), new ApfCapabilities(1, 2, 3));
assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3));
assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3));
}
@Test
public void testHasDataAccess() {
//hasDataAccess is only supported starting at apf version 4.
ApfCapabilities caps = new ApfCapabilities(1 /* apfVersionSupported */, 2, 3);
assertFalse(caps.hasDataAccess());
caps = new ApfCapabilities(4 /* apfVersionSupported */, 5, 6);
assertTrue(caps.hasDataAccess());
}
@Test
public void testGetApfDrop8023Frames() {
// Get com.android.internal.R.bool.config_apfDrop802_3Frames. The test cannot directly
// use R.bool.config_apfDrop802_3Frames because that is not a stable resource ID.
final int resId = mContext.getResources().getIdentifier("config_apfDrop802_3Frames",
"bool", "android");
final boolean shouldDrop8023Frames = mContext.getResources().getBoolean(resId);
final boolean actual = ApfCapabilities.getApfDrop8023Frames();
assertEquals(shouldDrop8023Frames, actual);
}
@Test
public void testGetApfEtherTypeBlackList() {
// Get com.android.internal.R.array.config_apfEthTypeBlackList. The test cannot directly
// use R.array.config_apfEthTypeBlackList because that is not a stable resource ID.
final int resId = mContext.getResources().getIdentifier("config_apfEthTypeBlackList",
"array", "android");
final int[] blacklistedEtherTypeArray = mContext.getResources().getIntArray(resId);
final int[] actual = ApfCapabilities.getApfEtherTypeBlackList();
assertNotNull(actual);
assertTrue(Arrays.equals(blacklistedEtherTypeArray, actual));
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2019 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 android.net.metrics;
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SmallTest
class ApfProgramEventTest {
private infix fun Int.hasFlag(flag: Int) = (this and (1 shl flag)) != 0
@Test
fun testBuilderAndParcel() {
val apfProgramEvent = ApfProgramEvent.Builder()
.setLifetime(1)
.setActualLifetime(2)
.setFilteredRas(3)
.setCurrentRas(4)
.setProgramLength(5)
.setFlags(true, true)
.build()
assertEquals(1, apfProgramEvent.lifetime)
assertEquals(2, apfProgramEvent.actualLifetime)
assertEquals(3, apfProgramEvent.filteredRas)
assertEquals(4, apfProgramEvent.currentRas)
assertEquals(5, apfProgramEvent.programLength)
assertEquals(ApfProgramEvent.flagsFor(true, true), apfProgramEvent.flags)
assertParcelSane(apfProgramEvent, 6)
}
@Test
fun testFlagsFor() {
var flags = ApfProgramEvent.flagsFor(false, false)
assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
flags = ApfProgramEvent.flagsFor(true, false)
assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
flags = ApfProgramEvent.flagsFor(false, true)
assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
flags = ApfProgramEvent.flagsFor(true, true)
assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2019 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 android.net.metrics
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SmallTest
class ApfStatsTest {
@Test
fun testBuilderAndParcel() {
val apfStats = ApfStats.Builder()
.setDurationMs(Long.MAX_VALUE)
.setReceivedRas(1)
.setMatchingRas(2)
.setDroppedRas(3)
.setZeroLifetimeRas(4)
.setParseErrors(5)
.setProgramUpdates(6)
.setProgramUpdatesAll(7)
.setProgramUpdatesAllowingMulticast(8)
.setMaxProgramSize(9)
.build()
assertEquals(Long.MAX_VALUE, apfStats.durationMs)
assertEquals(1, apfStats.receivedRas)
assertEquals(2, apfStats.matchingRas)
assertEquals(3, apfStats.droppedRas)
assertEquals(4, apfStats.zeroLifetimeRas)
assertEquals(5, apfStats.parseErrors)
assertEquals(6, apfStats.programUpdates)
assertEquals(7, apfStats.programUpdatesAll)
assertEquals(8, apfStats.programUpdatesAllowingMulticast)
assertEquals(9, apfStats.maxProgramSize)
assertParcelSane(apfStats, 10)
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2019 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 android.net.metrics
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
private const val FAKE_MESSAGE = "test"
@RunWith(AndroidJUnit4::class)
@SmallTest
class DhcpClientEventTest {
@Test
fun testBuilderAndParcel() {
val dhcpClientEvent = DhcpClientEvent.Builder()
.setMsg(FAKE_MESSAGE)
.setDurationMs(Integer.MAX_VALUE)
.build()
assertEquals(FAKE_MESSAGE, dhcpClientEvent.msg)
assertEquals(Integer.MAX_VALUE, dhcpClientEvent.durationMs)
assertParcelSane(dhcpClientEvent, 2)
}
}

View File

@@ -0,0 +1,65 @@
package android.net.metrics
import android.net.metrics.DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH
import android.net.metrics.DhcpErrorEvent.errorCodeWithOption
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.parcelingRoundTrip
import java.lang.reflect.Modifier
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
private const val TEST_ERROR_CODE = 12345
//DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java due to it's protected)
private const val DHCP_SUBNET_MASK = 1
@RunWith(AndroidJUnit4::class)
@SmallTest
class DhcpErrorEventTest {
@Test
fun testConstructor() {
val event = DhcpErrorEvent(TEST_ERROR_CODE)
assertEquals(TEST_ERROR_CODE, event.errorCode)
}
@Test
fun testParcelUnparcel() {
val event = DhcpErrorEvent(TEST_ERROR_CODE)
val parceled = parcelingRoundTrip(event)
assertEquals(TEST_ERROR_CODE, parceled.errorCode)
}
@Test
fun testErrorCodeWithOption() {
val errorCode = errorCodeWithOption(DHCP_INVALID_OPTION_LENGTH, DHCP_SUBNET_MASK);
assertTrue((DHCP_INVALID_OPTION_LENGTH and errorCode) == DHCP_INVALID_OPTION_LENGTH);
assertTrue((DHCP_SUBNET_MASK and errorCode) == DHCP_SUBNET_MASK);
}
@Test
fun testToString() {
val names = listOf("L2_ERROR", "L3_ERROR", "L4_ERROR", "DHCP_ERROR", "MISC_ERROR")
val errorFields = DhcpErrorEvent::class.java.declaredFields.filter {
it.type == Int::class.javaPrimitiveType
&& Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
&& it.name !in names
}
errorFields.forEach {
val intValue = it.getInt(null)
val stringValue = DhcpErrorEvent(intValue).toString()
assertTrue("Invalid string for error 0x%08X (field %s): %s".format(intValue, it.name,
stringValue),
stringValue.contains(it.name))
}
}
@Test
fun testToString_InvalidErrorCode() {
assertNotNull(DhcpErrorEvent(TEST_ERROR_CODE).toString())
}
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2019 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 android.net.metrics;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import android.net.ConnectivityMetricsEvent;
import android.net.IIpConnectivityMetrics;
import android.net.Network;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.BitUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class IpConnectivityLogTest {
private static final int FAKE_NET_ID = 100;
private static final int[] FAKE_TRANSPORT_TYPES = BitUtils.unpackBits(TRANSPORT_WIFI);
private static final long FAKE_TIME_STAMP = System.currentTimeMillis();
private static final String FAKE_INTERFACE_NAME = "test";
private static final IpReachabilityEvent FAKE_EV =
new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
@Mock IIpConnectivityMetrics mMockService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testLoggingEvents() throws Exception {
IpConnectivityLog logger = new IpConnectivityLog(mMockService);
assertTrue(logger.log(FAKE_EV));
assertTrue(logger.log(FAKE_TIME_STAMP, FAKE_EV));
assertTrue(logger.log(FAKE_NET_ID, FAKE_TRANSPORT_TYPES, FAKE_EV));
assertTrue(logger.log(new Network(FAKE_NET_ID), FAKE_TRANSPORT_TYPES, FAKE_EV));
assertTrue(logger.log(FAKE_INTERFACE_NAME, FAKE_EV));
assertTrue(logger.log(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID, TRANSPORT_WIFI,
FAKE_INTERFACE_NAME)));
List<ConnectivityMetricsEvent> got = verifyEvents(6);
assertEventsEqual(makeExpectedEvent(got.get(0).timestamp, 0, 0, null), got.get(0));
assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, 0, 0, null), got.get(1));
assertEventsEqual(makeExpectedEvent(got.get(2).timestamp, FAKE_NET_ID,
TRANSPORT_WIFI, null), got.get(2));
assertEventsEqual(makeExpectedEvent(got.get(3).timestamp, FAKE_NET_ID,
TRANSPORT_WIFI, null), got.get(3));
assertEventsEqual(makeExpectedEvent(got.get(4).timestamp, 0, 0, FAKE_INTERFACE_NAME),
got.get(4));
assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID,
TRANSPORT_WIFI, FAKE_INTERFACE_NAME), got.get(5));
}
@Test
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(makeExpectedEvent(
FAKE_TIME_STAMP + i * 100 + j,
FAKE_NET_ID + i * 100 + j,
((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR,
FAKE_INTERFACE_NAME)));
}
}
}.start();
}
List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 200);
Collections.sort(got, EVENT_COMPARATOR);
Iterator<ConnectivityMetricsEvent> iter = got.iterator();
for (int i = 0; i < nCallers; i++) {
for (int j = 0; j < nEvents; j++) {
final long expectedTimestamp = FAKE_TIME_STAMP + i * 100 + j;
final int expectedNetId = FAKE_NET_ID + i * 100 + j;
final long expectedTransports =
((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR;
assertEventsEqual(makeExpectedEvent(expectedTimestamp, expectedNetId,
expectedTransports, FAKE_INTERFACE_NAME), iter.next());
}
}
}
private 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();
}
private List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
return verifyEvents(n, 10);
}
private ConnectivityMetricsEvent makeExpectedEvent(long timestamp, int netId, long transports,
String ifname) {
ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
ev.timestamp = timestamp;
ev.data = FAKE_EV;
ev.netId = netId;
ev.transports = transports;
ev.ifname = ifname;
return ev;
}
/** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
private void assertEventsEqual(ConnectivityMetricsEvent expected,
ConnectivityMetricsEvent got) {
assertEquals(expected.data, got.data);
assertEquals(expected.timestamp, got.timestamp);
assertEquals(expected.netId, got.netId);
assertEquals(expected.transports, got.transports);
assertEquals(expected.ifname, got.ifname);
}
static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
Comparator.comparingLong((ev) -> ev.timestamp);
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2019 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 android.net.metrics
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SmallTest
class IpManagerEventTest {
@Test
fun testConstructorAndParcel() {
(IpManagerEvent.PROVISIONING_OK..IpManagerEvent.ERROR_INTERFACE_NOT_FOUND).forEach {
val ipManagerEvent = IpManagerEvent(it, Long.MAX_VALUE)
assertEquals(it, ipManagerEvent.eventType)
assertEquals(Long.MAX_VALUE, ipManagerEvent.durationMs)
assertParcelSane(ipManagerEvent, 2)
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2019 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 android.net.metrics
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SmallTest
class IpReachabilityEventTest {
@Test
fun testConstructorAndParcel() {
(IpReachabilityEvent.PROBE..IpReachabilityEvent.PROVISIONING_LOST_ORGANIC).forEach {
val ipReachabilityEvent = IpReachabilityEvent(it)
assertEquals(it, ipReachabilityEvent.eventType)
assertParcelSane(ipReachabilityEvent, 1)
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2019 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 android.net.metrics
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@SmallTest
class NetworkEventTest {
@Test
fun testConstructorAndParcel() {
(NetworkEvent.NETWORK_CONNECTED..NetworkEvent.NETWORK_PARTIAL_CONNECTIVITY).forEach {
var networkEvent = NetworkEvent(it)
assertEquals(it, networkEvent.eventType)
assertEquals(0, networkEvent.durationMs)
networkEvent = NetworkEvent(it, Long.MAX_VALUE)
assertEquals(it, networkEvent.eventType)
assertEquals(Long.MAX_VALUE, networkEvent.durationMs)
assertParcelSane(networkEvent, 2)
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2019 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 android.net.metrics
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
private const val NO_LIFETIME: Long = -1L
@RunWith(AndroidJUnit4::class)
@SmallTest
class RaEventTest {
@Test
fun testConstructorAndParcel() {
var raEvent = RaEvent.Builder().build()
assertEquals(NO_LIFETIME, raEvent.routerLifetime)
assertEquals(NO_LIFETIME, raEvent.prefixValidLifetime)
assertEquals(NO_LIFETIME, raEvent.prefixPreferredLifetime)
assertEquals(NO_LIFETIME, raEvent.routeInfoLifetime)
assertEquals(NO_LIFETIME, raEvent.rdnssLifetime)
assertEquals(NO_LIFETIME, raEvent.dnsslLifetime)
raEvent = RaEvent.Builder()
.updateRouterLifetime(1)
.updatePrefixValidLifetime(2)
.updatePrefixPreferredLifetime(3)
.updateRouteInfoLifetime(4)
.updateRdnssLifetime(5)
.updateDnsslLifetime(6)
.build()
assertEquals(1, raEvent.routerLifetime)
assertEquals(2, raEvent.prefixValidLifetime)
assertEquals(3, raEvent.prefixPreferredLifetime)
assertEquals(4, raEvent.routeInfoLifetime)
assertEquals(5, raEvent.rdnssLifetime)
assertEquals(6, raEvent.dnsslLifetime)
raEvent = RaEvent.Builder()
.updateRouterLifetime(Long.MIN_VALUE)
.updateRouterLifetime(Long.MAX_VALUE)
.build()
assertEquals(Long.MIN_VALUE, raEvent.routerLifetime)
raEvent = RaEvent(1, 2, 3, 4, 5, 6)
assertEquals(1, raEvent.routerLifetime)
assertEquals(2, raEvent.prefixValidLifetime)
assertEquals(3, raEvent.prefixPreferredLifetime)
assertEquals(4, raEvent.routeInfoLifetime)
assertEquals(5, raEvent.rdnssLifetime)
assertEquals(6, raEvent.dnsslLifetime)
assertParcelSane(raEvent, 6)
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2019 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 android.net.metrics
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
import java.lang.reflect.Modifier
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
private const val FIRST_VALIDATION: Int = 1 shl 8
private const val REVALIDATION: Int = 2 shl 8
@RunWith(AndroidJUnit4::class)
@SmallTest
class ValidationProbeEventTest {
private infix fun Int.hasType(type: Int) = (type and this) == type
@Test
fun testBuilderAndParcel() {
var validationProbeEvent = ValidationProbeEvent.Builder()
.setProbeType(ValidationProbeEvent.PROBE_DNS, false).build()
assertTrue(validationProbeEvent.probeType hasType REVALIDATION)
validationProbeEvent = ValidationProbeEvent.Builder()
.setDurationMs(Long.MAX_VALUE)
.setProbeType(ValidationProbeEvent.PROBE_DNS, true)
.setReturnCode(ValidationProbeEvent.DNS_SUCCESS)
.build()
assertEquals(Long.MAX_VALUE, validationProbeEvent.durationMs)
assertTrue(validationProbeEvent.probeType hasType ValidationProbeEvent.PROBE_DNS)
assertTrue(validationProbeEvent.probeType hasType FIRST_VALIDATION)
assertEquals(ValidationProbeEvent.DNS_SUCCESS, validationProbeEvent.returnCode)
assertParcelSane(validationProbeEvent, 3)
}
@Test
fun testGetProbeName() {
val probeFields = ValidationProbeEvent::class.java.declaredFields.filter {
it.type == Int::class.javaPrimitiveType
&& Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
&& it.name.contains("PROBE")
}
probeFields.forEach {
val intValue = it.getInt(null)
val stringValue = ValidationProbeEvent.getProbeName(intValue)
assertEquals(it.name, stringValue)
}
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright (C) 2020 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 android.net.netstats
import android.net.NetworkStats
import android.net.NetworkStats.DEFAULT_NETWORK_NO
import android.net.NetworkStats.DEFAULT_NETWORK_YES
import android.net.NetworkStats.Entry
import android.net.NetworkStats.IFACE_VT
import android.net.NetworkStats.METERED_NO
import android.net.NetworkStats.METERED_YES
import android.net.NetworkStats.ROAMING_NO
import android.net.NetworkStats.ROAMING_YES
import android.net.NetworkStats.SET_DEFAULT
import android.net.NetworkStats.SET_FOREGROUND
import android.net.NetworkStats.TAG_NONE
import android.os.Build
import androidx.test.filters.SmallTest
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.assertFieldCountEquals
import com.android.testutils.assertNetworkStatsEquals
import com.android.testutils.assertParcelingIsLossless
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import kotlin.test.assertEquals
@RunWith(JUnit4::class)
@SmallTest
class NetworkStatsApiTest {
@Rule
@JvmField
val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q)
private val testStatsEmpty = NetworkStats(0L, 0)
// Note that these variables need to be initialized outside of constructor, initialize
// here with methods that don't exist in Q devices will result in crash.
// stats1 and stats2 will have some entries with common keys, which are expected to
// be merged if performing add on these 2 stats.
private lateinit var testStats1: NetworkStats
private lateinit var testStats2: NetworkStats
// This is a result of adding stats1 and stats2, while the merging of common key items is
// subject to test later, this should not be initialized with for a loop to add stats1
// and stats2 above.
private lateinit var testStats3: NetworkStats
companion object {
private const val TEST_IFACE = "test0"
private const val TEST_UID1 = 1001
private const val TEST_UID2 = 1002
}
@Before
fun setUp() {
testStats1 = NetworkStats(0L, 0)
// Entries which only appear in set1.
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 37, 52, 1, 10, 4))
// Entries which are common for set1 and set2.
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 17, 2, 11, 1, 0))
.addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 40, 1, 0, 0, 8))
.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0))
assertEquals(8, testStats1.size())
testStats2 = NetworkStats(0L, 0)
// Entries which are common for set1 and set2.
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1))
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
.addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7))
.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0))
// Entry which only appears in set2.
.addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
assertEquals(5, testStats2.size())
testStats3 = NetworkStats(0L, 9)
// Entries which are unique either in stats1 or stats2.
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
.addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
// Entries which are common for stats1 and stats2 are being merged.
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 20, 17, 13, 32, 1))
.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50, 113, 11, 11, 49))
.addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 51, 3, 3, 4, 15))
.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7, 4, 8, 3, 0))
assertEquals(9, testStats3.size())
}
@Test
fun testAddEntry() {
val expectedEntriesInStats2 = arrayOf(
Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1),
Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45),
Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7),
Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0),
Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
// While testStats* are already initialized with addEntry, verify content added
// matches expectation.
for (i in expectedEntriesInStats2.indices) {
val entry = testStats2.getValues(i, null)
assertEquals(expectedEntriesInStats2[i], entry)
}
// Verify entry updated with addEntry.
val stats = testStats2.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12, -5, 7, 0, 9))
assertEquals(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16, -2, 9, 1, 9),
stats.getValues(3, null))
}
@Test
fun testAdd() {
var stats = NetworkStats(0L, 0)
assertNetworkStatsEquals(testStatsEmpty, stats)
stats = stats.add(testStats2)
assertNetworkStatsEquals(testStats2, stats)
stats = stats.add(testStats1)
// EMPTY + STATS2 + STATS1 = STATS3
assertNetworkStatsEquals(testStats3, stats)
}
@Test
fun testParcelUnparcel() {
assertParcelingIsLossless(testStatsEmpty)
assertParcelingIsLossless(testStats1)
assertParcelingIsLossless(testStats2)
assertFieldCountEquals(15, NetworkStats::class.java)
}
@Test
fun testDescribeContents() {
assertEquals(0, testStatsEmpty.describeContents())
assertEquals(0, testStats1.describeContents())
assertEquals(0, testStats2.describeContents())
assertEquals(0, testStats3.describeContents())
}
@Test
fun testSubtract() {
// STATS3 - STATS2 = STATS1
assertNetworkStatsEquals(testStats1, testStats3.subtract(testStats2))
// STATS3 - STATS1 = STATS2
assertNetworkStatsEquals(testStats2, testStats3.subtract(testStats1))
}
@Test
fun testMethodsDontModifyReceiver() {
listOf(testStatsEmpty, testStats1, testStats2, testStats3).forEach {
val origStats = it.clone()
it.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
it.add(testStats3)
it.subtract(testStats1)
assertNetworkStatsEquals(origStats, it)
}
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2019 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 android.net.util
import android.os.Build
import android.system.NetlinkSocketAddress
import android.system.Os
import android.system.OsConstants.AF_INET
import android.system.OsConstants.ETH_P_ALL
import android.system.OsConstants.IPPROTO_UDP
import android.system.OsConstants.RTMGRP_NEIGH
import android.system.OsConstants.SOCK_DGRAM
import android.system.PacketSocketAddress
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
private const val TEST_INDEX = 123
private const val TEST_PORT = 555
private const val FF_BYTE = 0xff.toByte()
@RunWith(AndroidJUnit4::class)
@SmallTest
class SocketUtilsTest {
@Rule @JvmField
val ignoreRule = DevSdkIgnoreRule()
@Test
fun testMakeNetlinkSocketAddress() {
val nlAddress = SocketUtils.makeNetlinkSocketAddress(TEST_PORT, RTMGRP_NEIGH)
if (nlAddress is NetlinkSocketAddress) {
assertEquals(TEST_PORT, nlAddress.getPortId())
assertEquals(RTMGRP_NEIGH, nlAddress.getGroupsMask())
} else {
fail("Not NetlinkSocketAddress object")
}
}
@Test
fun testMakePacketSocketAddress_Q() {
val pkAddress = SocketUtils.makePacketSocketAddress(ETH_P_ALL, TEST_INDEX)
assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
val pkAddress2 = SocketUtils.makePacketSocketAddress(TEST_INDEX, ByteArray(6) { FF_BYTE })
assertTrue("Not PacketSocketAddress object", pkAddress2 is PacketSocketAddress)
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
fun testMakePacketSocketAddress() {
val pkAddress = SocketUtils.makePacketSocketAddress(
ETH_P_ALL, TEST_INDEX, ByteArray(6) { FF_BYTE })
assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
}
@Test
fun testCloseSocket() {
// Expect no exception happening with null object.
SocketUtils.closeSocket(null)
val fd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
assertTrue(fd.valid())
SocketUtils.closeSocket(fd)
assertFalse(fd.valid())
// Expecting socket should be still invalid even closed socket again.
SocketUtils.closeSocket(fd)
assertFalse(fd.valid())
}
}

39
tests/deflake/Android.bp Normal file
View File

@@ -0,0 +1,39 @@
//
// Copyright (C) 2019 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 {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
java_test_host {
name: "FrameworksNetDeflakeTest",
srcs: ["src/**/*.kt"],
libs: [
"junit",
"tradefed",
],
static_libs: [
"kotlin-test",
"net-host-tests-utils",
],
data: [":FrameworksNetTests"],
test_suites: ["device-tests"],
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2019 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.net
import com.android.testutils.host.DeflakeHostTestBase
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
import org.junit.runner.RunWith
@RunWith(DeviceJUnit4ClassRunner::class)
class FrameworksNetDeflakeTest: DeflakeHostTestBase() {
override val runCount = 20
override val testApkFilename = "FrameworksNetTests.apk"
override val testClasses = listOf("com.android.server.ConnectivityServiceTest")
}

View File

@@ -0,0 +1,76 @@
//
// Copyright (C) 2019 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 {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
android_test {
name: "FrameworksNetIntegrationTests",
platform_apis: true,
certificate: "platform",
srcs: [
"src/**/*.kt",
"src/**/*.aidl",
],
libs: [
"android.test.mock",
],
static_libs: [
"NetworkStackApiStableLib",
"androidx.test.ext.junit",
"frameworks-net-integration-testutils",
"kotlin-reflect",
"mockito-target-extended-minus-junit4",
"net-tests-utils",
"service-connectivity",
"services.core",
"services.net",
"testables",
],
test_suites: ["device-tests"],
use_embedded_native_libs: true,
jni_libs: [
// For mockito extended
"libdexmakerjvmtiagent",
"libstaticjvmtiagent",
// android_library does not include JNI libs: include NetworkStack dependencies here
"libnativehelper_compat_libc++",
"libnetworkstackutilsjni",
],
}
// Utilities for testing framework code both in integration and unit tests.
java_library {
name: "frameworks-net-integration-testutils",
srcs: ["util/**/*.java", "util/**/*.kt"],
static_libs: [
"androidx.annotation_annotation",
"androidx.test.rules",
"junit",
"net-tests-utils",
],
libs: [
"service-connectivity",
"services.core",
"services.net",
],
}

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2019 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.
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.net.integrationtests">
<!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
<!-- PermissionMonitor sets network permissions for each user -->
<uses-permission android:name="android.permission.MANAGE_USERS"/>
<!-- ConnectivityService sends notifications to BatteryStats -->
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS"/>
<!-- Reading network status -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.NETWORK_FACTORY"/>
<!-- Obtain LinkProperties callbacks with sensitive fields -->
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.NETWORK_STACK"/>
<uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY"/>
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<!-- Reading DeviceConfig flags -->
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<!-- Querying the resources package -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<application android:debuggable="true">
<uses-library android:name="android.test.runner"/>
<!-- This manifest is merged with the base manifest of the real NetworkStack app.
Remove the NetworkStackService from the base (real) manifest, and replace with a test
service that responds to the same intent -->
<service android:name=".TestNetworkStackService"
android:process="com.android.server.net.integrationtests.testnetworkstack"
android:exported="true">
<intent-filter>
<action android:name="android.net.INetworkStackConnector.Test"/>
</intent-filter>
</service>
<service android:name=".NetworkStackInstrumentationService"
android:process="com.android.server.net.integrationtests.testnetworkstack"
android:exported="true">
<intent-filter>
<action android:name=".INetworkStackInstrumentation"/>
</intent-filter>
</service>
<service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
android:process="com.android.server.net.integrationtests.testnetworkstack"
android:permission="android.permission.BIND_JOB_SERVICE"/>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.server.net.integrationtests"
android:label="Frameworks Net Integration Tests"/>
</manifest>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Override configuration for testing. The below settings use the config_ variants, which are
normally used by RROs to override the setting with highest priority. -->
<integer name="config_captive_portal_dns_probe_timeout">12500</integer>
<string name="config_captive_portal_http_url" translatable="false">http://test.android.com</string>
<string name="config_captive_portal_https_url" translatable="false">https://secure.test.android.com</string>
<string-array name="config_captive_portal_fallback_urls" translatable="false">
<item>http://fallback1.android.com</item>
<item>http://fallback2.android.com</item>
</string-array>
<string-array name="config_captive_portal_fallback_probe_specs" translatable="false">
</string-array>
</resources>

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2019 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 android.net
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.IBinder
import com.android.server.net.integrationtests.TestNetworkStackService
import org.mockito.Mockito.any
import org.mockito.Mockito.spy
import org.mockito.Mockito.timeout
import org.mockito.Mockito.verify
import kotlin.test.fail
const val TEST_ACTION_SUFFIX = ".Test"
class TestNetworkStackClient(context: Context) : NetworkStackClient(TestDependencies(context)) {
// TODO: consider switching to TrackRecord for more expressive checks
private val lastCallbacks = HashMap<Network, INetworkMonitorCallbacks>()
private class TestDependencies(private val context: Context) : Dependencies {
override fun addToServiceManager(service: IBinder) = Unit
override fun checkCallerUid() = Unit
override fun getConnectivityModuleConnector(): ConnectivityModuleConnector {
return ConnectivityModuleConnector { _, _, _, inSystemProcess ->
getNetworkStackIntent(inSystemProcess)
}.also { it.init(context) }
}
private fun getNetworkStackIntent(inSystemProcess: Boolean): Intent? {
// Simulate out-of-system-process config: in-process service not found (null intent)
if (inSystemProcess) return null
val intent = Intent(INetworkStackConnector::class.qualifiedName + TEST_ACTION_SUFFIX)
val serviceName = TestNetworkStackService::class.qualifiedName
?: fail("TestNetworkStackService name not found")
intent.component = ComponentName(context.packageName, serviceName)
return intent
}
}
// base may be an instance of an inaccessible subclass, so non-spyable.
// Use a known open class that delegates to the original instance for all methods except
// asBinder. asBinder needs to use its own non-delegated implementation as otherwise it would
// return a binder token to a class that is not spied on.
open class NetworkMonitorCallbacksWrapper(private val base: INetworkMonitorCallbacks) :
INetworkMonitorCallbacks.Stub(), INetworkMonitorCallbacks by base {
// asBinder is implemented by both base class and delegate: specify explicitly
override fun asBinder(): IBinder {
return super.asBinder()
}
}
override fun makeNetworkMonitor(network: Network, name: String?, cb: INetworkMonitorCallbacks) {
val cbSpy = spy(NetworkMonitorCallbacksWrapper(cb))
lastCallbacks[network] = cbSpy
super.makeNetworkMonitor(network, name, cbSpy)
}
fun verifyNetworkMonitorCreated(network: Network, timeoutMs: Long) {
val cb = lastCallbacks[network]
?: fail("NetworkMonitor for network $network not requested")
verify(cb, timeout(timeoutMs)).onNetworkMonitorCreated(any())
}
}

View File

@@ -0,0 +1,258 @@
/*
* Copyright (C) 2019 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.net.integrationtests
import android.app.usage.NetworkStatsManager
import android.content.ComponentName
import android.content.Context
import android.content.Context.BIND_AUTO_CREATE
import android.content.Context.BIND_IMPORTANT
import android.content.Intent
import android.content.ServiceConnection
import android.net.ConnectivityManager
import android.net.IDnsResolver
import android.net.INetd
import android.net.LinkProperties
import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkRequest
import android.net.TestNetworkStackClient
import android.net.Uri
import android.net.metrics.IpConnectivityLog
import android.os.ConditionVariable
import android.os.IBinder
import android.os.SystemConfigManager
import android.os.UserHandle
import android.testing.TestableContext
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.ConnectivityService
import com.android.server.NetworkAgentWrapper
import com.android.server.TestNetIdManager
import com.android.server.connectivity.MockableSystemProperties
import com.android.server.connectivity.ProxyTracker
import com.android.testutils.TestableNetworkCallback
import org.junit.After
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.AdditionalAnswers
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
import org.mockito.MockitoAnnotations
import org.mockito.Spy
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlin.test.fail
const val SERVICE_BIND_TIMEOUT_MS = 5_000L
const val TEST_TIMEOUT_MS = 10_000L
/**
* Test that exercises an instrumented version of ConnectivityService against an instrumented
* NetworkStack in a different test process.
*/
@RunWith(AndroidJUnit4::class)
class ConnectivityServiceIntegrationTest {
// lateinit used here for mocks as they need to be reinitialized between each test and the test
// should crash if they are used before being initialized.
@Mock
private lateinit var statsManager: NetworkStatsManager
@Mock
private lateinit var log: IpConnectivityLog
@Mock
private lateinit var netd: INetd
@Mock
private lateinit var dnsResolver: IDnsResolver
@Mock
private lateinit var systemConfigManager: SystemConfigManager
@Spy
private var context = TestableContext(realContext)
// lateinit for these three classes under test, as they should be reset to a different instance
// for every test but should always be initialized before use (or the test should crash).
private lateinit var networkStackClient: TestNetworkStackClient
private lateinit var service: ConnectivityService
private lateinit var cm: ConnectivityManager
companion object {
// lateinit for this binder token, as it must be initialized before any test code is run
// and use of it before init should crash the test.
private lateinit var nsInstrumentation: INetworkStackInstrumentation
private val bindingCondition = ConditionVariable(false)
private val realContext get() = InstrumentationRegistry.getInstrumentation().context
private val httpProbeUrl get() =
realContext.getResources().getString(R.string.config_captive_portal_http_url)
private val httpsProbeUrl get() =
realContext.getResources().getString(R.string.config_captive_portal_https_url)
private class InstrumentationServiceConnection : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.i("TestNetworkStack", "Service connected")
try {
if (service == null) fail("Error binding to NetworkStack instrumentation")
if (::nsInstrumentation.isInitialized) fail("Service already connected")
nsInstrumentation = INetworkStackInstrumentation.Stub.asInterface(service)
} finally {
bindingCondition.open()
}
}
override fun onServiceDisconnected(name: ComponentName?) = Unit
}
@BeforeClass
@JvmStatic
fun setUpClass() {
val intent = Intent(realContext, NetworkStackInstrumentationService::class.java)
intent.action = INetworkStackInstrumentation::class.qualifiedName
assertTrue(realContext.bindService(intent, InstrumentationServiceConnection(),
BIND_AUTO_CREATE or BIND_IMPORTANT),
"Error binding to instrumentation service")
assertTrue(bindingCondition.block(SERVICE_BIND_TIMEOUT_MS),
"Timed out binding to instrumentation service " +
"after $SERVICE_BIND_TIMEOUT_MS ms")
}
}
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
val asUserCtx = mock(Context::class.java, AdditionalAnswers.delegatesTo<Context>(context))
doReturn(UserHandle.ALL).`when`(asUserCtx).user
doReturn(asUserCtx).`when`(context).createContextAsUser(eq(UserHandle.ALL), anyInt())
doNothing().`when`(context).sendStickyBroadcast(any(), any())
doReturn(Context.SYSTEM_CONFIG_SERVICE).`when`(context)
.getSystemServiceName(SystemConfigManager::class.java)
doReturn(systemConfigManager).`when`(context)
.getSystemService(Context.SYSTEM_CONFIG_SERVICE)
doReturn(IntArray(0)).`when`(systemConfigManager).getSystemPermissionUids(anyString())
networkStackClient = TestNetworkStackClient(realContext)
networkStackClient.init()
networkStackClient.start()
service = TestConnectivityService(makeDependencies())
cm = ConnectivityManager(context, service)
context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
context.addMockSystemService(Context.NETWORK_STATS_SERVICE, statsManager)
service.systemReadyInternal()
}
private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
context, dnsResolver, log, netd, deps)
private fun makeDependencies(): ConnectivityService.Dependencies {
val deps = spy(ConnectivityService.Dependencies())
doReturn(networkStackClient).`when`(deps).networkStack
doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any())
doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties
doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager()
return deps
}
@After
fun tearDown() {
nsInstrumentation.clearAllState()
}
@Test
fun testValidation() {
val request = NetworkRequest.Builder()
.clearCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
.build()
val testCallback = TestableNetworkCallback()
cm.registerNetworkCallback(request, testCallback)
nsInstrumentation.addHttpResponse(HttpResponse(httpProbeUrl, responseCode = 204))
nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))
val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), null /* ncTemplate */,
context)
networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
na.addCapability(NET_CAPABILITY_INTERNET)
na.connect()
testCallback.expectAvailableThenValidatedCallbacks(na.network, TEST_TIMEOUT_MS)
assertEquals(2, nsInstrumentation.getRequestUrls().size)
}
@Test
fun testCapportApi() {
val request = NetworkRequest.Builder()
.clearCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
.build()
val testCb = TestableNetworkCallback()
val apiUrl = "https://capport.android.com"
cm.registerNetworkCallback(request, testCb)
nsInstrumentation.addHttpResponse(HttpResponse(
apiUrl,
"""
|{
| "captive": true,
| "user-portal-url": "https://login.capport.android.com",
| "venue-info-url": "https://venueinfo.capport.android.com"
|}
""".trimMargin()))
// Tests will fail if a non-mocked query is received: mock the HTTPS probe, but not the
// HTTP probe as it should not be sent.
// Even if the HTTPS probe succeeds, a portal should be detected as the API takes precedence
// in that case.
nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))
val lp = LinkProperties()
lp.captivePortalApiUrl = Uri.parse(apiUrl)
val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, lp, null /* ncTemplate */, context)
networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
na.addCapability(NET_CAPABILITY_INTERNET)
na.connect()
testCb.expectAvailableCallbacks(na.network, validated = false, tmt = TEST_TIMEOUT_MS)
val capportData = testCb.expectLinkPropertiesThat(na, TEST_TIMEOUT_MS) {
it.captivePortalData != null
}.lp.captivePortalData
assertNotNull(capportData)
assertTrue(capportData.isCaptive)
assertEquals(Uri.parse("https://login.capport.android.com"), capportData.userPortalUrl)
assertEquals(Uri.parse("https://venueinfo.capport.android.com"), capportData.venueInfoUrl)
val nc = testCb.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, na, TEST_TIMEOUT_MS)
assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED))
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 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.net.integrationtests;
parcelable HttpResponse;

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2019 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.net.integrationtests
import android.os.Parcel
import android.os.Parcelable
data class HttpResponse(
val requestUrl: String,
val responseCode: Int,
val content: String = "",
val redirectUrl: String? = null
) : Parcelable {
constructor(p: Parcel): this(p.readString(), p.readInt(), p.readString(), p.readString())
constructor(requestUrl: String, contentBody: String): this(
requestUrl,
responseCode = 200,
content = contentBody,
redirectUrl = null)
override fun writeToParcel(dest: Parcel, flags: Int) {
with(dest) {
writeString(requestUrl)
writeInt(responseCode)
writeString(content)
writeString(redirectUrl)
}
}
override fun describeContents() = 0
companion object CREATOR : Parcelable.Creator<HttpResponse> {
override fun createFromParcel(source: Parcel) = HttpResponse(source)
override fun newArray(size: Int) = arrayOfNulls<HttpResponse?>(size)
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2019 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.net.integrationtests;
import com.android.server.net.integrationtests.HttpResponse;
interface INetworkStackInstrumentation {
void clearAllState();
void addHttpResponse(in HttpResponse response);
List<String> getRequestUrls();
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2019 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.net.integrationtests
import android.app.Service
import android.content.Intent
import java.net.URL
import java.util.Collections
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.collections.ArrayList
import kotlin.test.fail
/**
* An instrumentation interface for the NetworkStack that allows controlling behavior to
* facilitate integration tests.
*/
class NetworkStackInstrumentationService : Service() {
override fun onBind(intent: Intent) = InstrumentationConnector.asBinder()
object InstrumentationConnector : INetworkStackInstrumentation.Stub() {
private val httpResponses = ConcurrentHashMap<String, ConcurrentLinkedQueue<HttpResponse>>()
.run {
withDefault { key -> getOrPut(key) { ConcurrentLinkedQueue() } }
}
private val httpRequestUrls = Collections.synchronizedList(ArrayList<String>())
/**
* Called when an HTTP request is being processed by NetworkMonitor. Returns the response
* that should be simulated.
*/
fun processRequest(url: URL): HttpResponse {
val strUrl = url.toString()
httpRequestUrls.add(strUrl)
return httpResponses[strUrl]?.poll()
?: fail("No mocked response for request: $strUrl. " +
"Mocked URL keys are: ${httpResponses.keys}")
}
/**
* Clear all state of this connector. This is intended for use between two tests, so all
* state should be reset as if the connector was just created.
*/
override fun clearAllState() {
httpResponses.clear()
httpRequestUrls.clear()
}
/**
* Add a response to a future HTTP request.
*
* <p>For any subsequent HTTP/HTTPS query, the first response with a matching URL will be
* used to mock the query response.
*
* <p>All requests that are expected to be sent must have a mock response: if an unexpected
* request is seen, the test will fail.
*/
override fun addHttpResponse(response: HttpResponse) {
httpResponses.getValue(response.requestUrl).add(response)
}
/**
* Get the ordered list of request URLs that have been sent by NetworkMonitor, and were
* answered based on mock responses.
*/
override fun getRequestUrls(): List<String> {
return ArrayList(httpRequestUrls)
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2019 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.net.integrationtests
import android.app.Service
import android.content.Context
import android.content.Intent
import android.net.INetworkMonitorCallbacks
import android.net.Network
import android.net.metrics.IpConnectivityLog
import android.net.util.SharedLog
import android.os.IBinder
import com.android.networkstack.netlink.TcpSocketTracker
import com.android.server.NetworkStackService
import com.android.server.NetworkStackService.NetworkMonitorConnector
import com.android.server.NetworkStackService.NetworkStackConnector
import com.android.server.connectivity.NetworkMonitor
import com.android.server.net.integrationtests.NetworkStackInstrumentationService.InstrumentationConnector
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
import java.io.ByteArrayInputStream
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLConnection
import java.nio.charset.StandardCharsets
private const val TEST_NETID = 42
/**
* Android service that can return an [android.net.INetworkStackConnector] which can be instrumented
* through [NetworkStackInstrumentationService].
* Useful in tests to create test instrumented NetworkStack components that can receive
* instrumentation commands through [NetworkStackInstrumentationService].
*/
class TestNetworkStackService : Service() {
override fun onBind(intent: Intent): IBinder = TestNetworkStackConnector(makeTestContext())
private fun makeTestContext() = spy(applicationContext).also {
doReturn(mock(IBinder::class.java)).`when`(it).getSystemService(Context.NETD_SERVICE)
}
private class TestPermissionChecker : NetworkStackService.PermissionChecker() {
override fun enforceNetworkStackCallingPermission() = Unit
}
private class NetworkMonitorDeps(private val privateDnsBypassNetwork: Network) :
NetworkMonitor.Dependencies() {
override fun getPrivateDnsBypassNetwork(network: Network?) = privateDnsBypassNetwork
}
private inner class TestNetworkStackConnector(context: Context) : NetworkStackConnector(
context, TestPermissionChecker(), NetworkStackService.Dependencies()) {
private val network = Network(TEST_NETID)
private val privateDnsBypassNetwork = TestNetwork(TEST_NETID)
private inner class TestNetwork(netId: Int) : Network(netId) {
override fun openConnection(url: URL): URLConnection {
val response = InstrumentationConnector.processRequest(url)
val responseBytes = response.content.toByteArray(StandardCharsets.UTF_8)
val connection = mock(HttpURLConnection::class.java)
doReturn(response.responseCode).`when`(connection).responseCode
doReturn(responseBytes.size.toLong()).`when`(connection).contentLengthLong
doReturn(response.redirectUrl).`when`(connection).getHeaderField("location")
doReturn(ByteArrayInputStream(responseBytes)).`when`(connection).inputStream
return connection
}
}
override fun makeNetworkMonitor(
network: Network,
name: String?,
cb: INetworkMonitorCallbacks
) {
val nm = NetworkMonitor(this@TestNetworkStackService, cb,
this.network,
mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
mock(NetworkStackService.NetworkStackServiceManager::class.java),
NetworkMonitorDeps(privateDnsBypassNetwork),
mock(TcpSocketTracker::class.java))
cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker()))
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2019 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
*/
@file:JvmName("ConnectivityServiceTestUtils")
package com.android.server
import android.net.ConnectivityManager.TYPE_BLUETOOTH
import android.net.ConnectivityManager.TYPE_ETHERNET
import android.net.ConnectivityManager.TYPE_MOBILE
import android.net.ConnectivityManager.TYPE_NONE
import android.net.ConnectivityManager.TYPE_TEST
import android.net.ConnectivityManager.TYPE_VPN
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkCapabilities.TRANSPORT_VPN
import android.net.NetworkCapabilities.TRANSPORT_WIFI
fun transportToLegacyType(transport: Int) = when (transport) {
TRANSPORT_BLUETOOTH -> TYPE_BLUETOOTH
TRANSPORT_CELLULAR -> TYPE_MOBILE
TRANSPORT_ETHERNET -> TYPE_ETHERNET
TRANSPORT_TEST -> TYPE_TEST
TRANSPORT_VPN -> TYPE_VPN
TRANSPORT_WIFI -> TYPE_WIFI
else -> TYPE_NONE
}

View File

@@ -0,0 +1,377 @@
/*
* Copyright (C) 2019 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;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
import android.net.NetworkSpecifier;
import android.net.QosFilter;
import android.net.SocketKeepalive;
import android.os.ConditionVariable;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import android.util.Range;
import com.android.net.module.util.ArrayTrackRecord;
import com.android.server.connectivity.ConnectivityConstants;
import com.android.testutils.HandlerUtils;
import com.android.testutils.TestableNetworkCallback;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
private final NetworkCapabilities mNetworkCapabilities;
private final HandlerThread mHandlerThread;
private final Context mContext;
private final String mLogTag;
private final NetworkAgentConfig mNetworkAgentConfig;
private final ConditionVariable mDisconnected = new ConditionVariable();
private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
private final AtomicBoolean mConnected = new AtomicBoolean(false);
private int mScore;
private NetworkAgent mNetworkAgent;
private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
// Controls how test network agent is going to wait before responding to keepalive
// start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem.
private long mKeepaliveResponseDelay = 0L;
private Integer mExpectedKeepaliveSlot = null;
private final ArrayTrackRecord<CallbackType>.ReadHead mCallbackHistory =
new ArrayTrackRecord<CallbackType>().newReadHead();
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
NetworkCapabilities ncTemplate, Context context) throws Exception {
final int type = transportToLegacyType(transport);
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
mNetworkCapabilities.addTransportType(transport);
switch (transport) {
case TRANSPORT_ETHERNET:
mScore = 70;
break;
case TRANSPORT_WIFI:
mScore = 60;
break;
case TRANSPORT_CELLULAR:
mScore = 50;
break;
case TRANSPORT_WIFI_AWARE:
mScore = 20;
break;
case TRANSPORT_VPN:
mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
// VPNs deduce the SUSPENDED capability from their underlying networks and there
// is no public API to let VPN services set it.
mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
break;
default:
throw new UnsupportedOperationException("unimplemented network type");
}
mContext = context;
mLogTag = "Mock-" + typeName;
mHandlerThread = new HandlerThread(mLogTag);
mHandlerThread.start();
// extraInfo is set to "" by default in NetworkAgentConfig.
final String extraInfo = (transport == TRANSPORT_CELLULAR) ? "internet.apn" : "";
mNetworkAgentConfig = new NetworkAgentConfig.Builder()
.setLegacyType(type)
.setLegacyTypeName(typeName)
.setLegacyExtraInfo(extraInfo)
.build();
mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig);
}
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
final NetworkAgentConfig nac) throws Exception {
return new InstrumentedNetworkAgent(this, linkProperties, nac);
}
public static class InstrumentedNetworkAgent extends NetworkAgent {
private final NetworkAgentWrapper mWrapper;
private static final String PROVIDER_NAME = "InstrumentedNetworkAgentProvider";
public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
NetworkAgentConfig nac) {
super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag,
wrapper.mNetworkCapabilities, lp, wrapper.mScore, nac,
new NetworkProvider(wrapper.mContext, wrapper.mHandlerThread.getLooper(),
PROVIDER_NAME));
mWrapper = wrapper;
register();
}
@Override
public void unwanted() {
mWrapper.mDisconnected.open();
}
@Override
public void startSocketKeepalive(Message msg) {
int slot = msg.arg1;
if (mWrapper.mExpectedKeepaliveSlot != null) {
assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
}
mWrapper.mHandlerThread.getThreadHandler().postDelayed(
() -> onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError),
mWrapper.mKeepaliveResponseDelay);
}
@Override
public void stopSocketKeepalive(Message msg) {
final int slot = msg.arg1;
mWrapper.mHandlerThread.getThreadHandler().postDelayed(
() -> onSocketKeepaliveEvent(slot, mWrapper.mStopKeepaliveError),
mWrapper.mKeepaliveResponseDelay);
}
@Override
public void onQosCallbackRegistered(final int qosCallbackId,
final @NonNull QosFilter filter) {
Log.i(mWrapper.mLogTag, "onQosCallbackRegistered");
mWrapper.mCallbackHistory.add(
new CallbackType.OnQosCallbackRegister(qosCallbackId, filter));
}
@Override
public void onQosCallbackUnregistered(final int qosCallbackId) {
Log.i(mWrapper.mLogTag, "onQosCallbackUnregistered");
mWrapper.mCallbackHistory.add(new CallbackType.OnQosCallbackUnregister(qosCallbackId));
}
@Override
protected void preventAutomaticReconnect() {
mWrapper.mPreventReconnectReceived.open();
}
@Override
protected void addKeepalivePacketFilter(Message msg) {
Log.i(mWrapper.mLogTag, "Add keepalive packet filter.");
}
@Override
protected void removeKeepalivePacketFilter(Message msg) {
Log.i(mWrapper.mLogTag, "Remove keepalive packet filter.");
}
}
public void adjustScore(int change) {
mScore += change;
mNetworkAgent.sendNetworkScore(mScore);
}
public int getScore() {
return mScore;
}
public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated);
}
public void addCapability(int capability) {
mNetworkCapabilities.addCapability(capability);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
public void removeCapability(int capability) {
mNetworkCapabilities.removeCapability(capability);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
public void setUids(Set<Range<Integer>> uids) {
mNetworkCapabilities.setUids(uids);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
public void setSignalStrength(int signalStrength) {
mNetworkCapabilities.setSignalStrength(signalStrength);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) {
mNetworkCapabilities.set(nc);
if (sendToConnectivityService) {
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
}
public void connect() {
if (!mConnected.compareAndSet(false /* expect */, true /* update */)) {
// compareAndSet returns false when the value couldn't be updated because it did not
// match the expected value.
fail("Test NetworkAgents can only be connected once");
}
mNetworkAgent.markConnected();
}
public void suspend() {
removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
}
public void resume() {
addCapability(NET_CAPABILITY_NOT_SUSPENDED);
}
public void disconnect() {
mNetworkAgent.unregister();
}
@Override
public Network getNetwork() {
return mNetworkAgent.getNetwork();
}
public void expectPreventReconnectReceived(long timeoutMs) {
assertTrue(mPreventReconnectReceived.block(timeoutMs));
}
public void expectDisconnected(long timeoutMs) {
assertTrue(mDisconnected.block(timeoutMs));
}
public void sendLinkProperties(LinkProperties lp) {
mNetworkAgent.sendLinkProperties(lp);
}
public void setStartKeepaliveEvent(int reason) {
mStartKeepaliveError = reason;
}
public void setStopKeepaliveEvent(int reason) {
mStopKeepaliveError = reason;
}
public void setKeepaliveResponseDelay(long delay) {
mKeepaliveResponseDelay = delay;
}
public void setExpectedKeepaliveSlot(Integer slot) {
mExpectedKeepaliveSlot = slot;
}
public NetworkAgent getNetworkAgent() {
return mNetworkAgent;
}
public NetworkCapabilities getNetworkCapabilities() {
return mNetworkCapabilities;
}
public int getLegacyType() {
return mNetworkAgentConfig.getLegacyType();
}
public String getExtraInfo() {
return mNetworkAgentConfig.getLegacyExtraInfo();
}
public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() {
return mCallbackHistory;
}
public void waitForIdle(long timeoutMs) {
HandlerUtils.waitForIdle(mHandlerThread, timeoutMs);
}
abstract static class CallbackType {
final int mQosCallbackId;
protected CallbackType(final int qosCallbackId) {
mQosCallbackId = qosCallbackId;
}
static class OnQosCallbackRegister extends CallbackType {
final QosFilter mFilter;
OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter) {
super(qosCallbackId);
mFilter = filter;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final OnQosCallbackRegister that = (OnQosCallbackRegister) o;
return mQosCallbackId == that.mQosCallbackId
&& Objects.equals(mFilter, that.mFilter);
}
@Override
public int hashCode() {
return Objects.hash(mQosCallbackId, mFilter);
}
}
static class OnQosCallbackUnregister extends CallbackType {
OnQosCallbackUnregister(final int qosCallbackId) {
super(qosCallbackId);
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final OnQosCallbackUnregister that = (OnQosCallbackUnregister) o;
return mQosCallbackId == that.mQosCallbackId;
}
@Override
public int hashCode() {
return Objects.hash(mQosCallbackId);
}
}
}
public boolean isBypassableVpn() {
return mNetworkAgentConfig.isBypassableVpn();
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2019 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
import java.util.concurrent.atomic.AtomicInteger
/**
* A [NetIdManager] that generates ID starting from [NetIdManager.MAX_NET_ID] and decreasing, rather
* than starting from [NetIdManager.MIN_NET_ID] and increasing.
*
* Useful for testing ConnectivityService, to minimize the risk of test ConnectivityService netIDs
* overlapping with netIDs used by the real ConnectivityService on the device.
*
* IDs may still overlap if many networks have been used on the device (so the "real" netIDs
* are close to MAX_NET_ID), but this is typically not the case when running unit tests. Also, there
* is no way to fully solve the overlap issue without altering ID allocation in non-test code, as
* the real ConnectivityService could start using netIds that have been used by the test in the
* past.
*/
class TestNetIdManager : NetIdManager() {
private val nextId = AtomicInteger(MAX_NET_ID)
override fun reserveNetId() = nextId.decrementAndGet()
override fun releaseNetId(id: Int) = Unit
fun peekNextNetId() = nextId.get() - 1
}

View File

@@ -0,0 +1,31 @@
// This test exists only because the jni_libs list for these tests is difficult to
// maintain: the test itself only depends on libnetworkstatsfactorytestjni, but the test
// fails to load that library unless *all* the dependencies of that library are explicitly
// listed in jni_libs. This means that whenever any of the dependencies changes the test
// starts failing and breaking presubmits in frameworks/base. We cannot easily put
// FrameworksNetTests into global presubmit because they are at times flaky, but this
// test is effectively empty beyond validating that the libraries load correctly, and
// thus should be stable enough to put in global presubmit.
//
// TODO: remove this hack when there is a better solution for jni_libs that includes
// dependent libraries.
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
android_test {
name: "FrameworksNetSmokeTests",
defaults: ["FrameworksNetTests-jni-defaults"],
srcs: ["java/SmokeTest.java"],
test_suites: ["device-tests"],
static_libs: [
"androidx.test.rules",
"mockito-target-minus-junit4",
"services.core",
],
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2019 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.tests.net.smoketest">
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.frameworks.tests.net.smoketest"
android:label="Frameworks Networking Smoke Tests" />
</manifest>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2019 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.
-->
<configuration description="Runs Frameworks Networking Smoke Tests.">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="FrameworksNetSmokeTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<option name="test-tag" value="FrameworksNetSmokeTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.frameworks.tests.net.smoketest" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2019 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.net;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public final class SmokeTest {
@Test
public void testLoadJni() {
System.loadLibrary("networkstatsfactorytestjni");
assertEquals(0, 0x00);
}
}

87
tests/unit/Android.bp Normal file
View File

@@ -0,0 +1,87 @@
//########################################################################
// Build FrameworksNetTests package
//########################################################################
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
java_defaults {
name: "FrameworksNetTests-jni-defaults",
jni_libs: [
"ld-android",
"libbacktrace",
"libbase",
"libbinder",
"libbpf",
"libbpf_android",
"libc++",
"libcgrouprc",
"libcrypto",
"libcutils",
"libdl_android",
"libhidl-gen-utils",
"libhidlbase",
"libjsoncpp",
"liblog",
"liblzma",
"libnativehelper",
"libnetdbpf",
"libnetdutils",
"libnetworkstatsfactorytestjni",
"libpackagelistparser",
"libpcre2",
"libprocessgroup",
"libselinux",
"libtinyxml2",
"libui",
"libunwindstack",
"libutils",
"libutilscallstack",
"libvndksupport",
"libziparchive",
"libz",
"netd_aidl_interface-V5-cpp",
],
}
android_test {
name: "FrameworksNetTests",
defaults: ["FrameworksNetTests-jni-defaults"],
srcs: [
"java/**/*.java",
"java/**/*.kt",
],
platform_apis: true,
test_suites: ["device-tests"],
certificate: "platform",
jarjar_rules: "jarjar-rules.txt",
static_libs: [
"androidx.test.rules",
"bouncycastle-repackaged-unbundled",
"FrameworksNetCommonTests",
"frameworks-base-testutils",
"frameworks-net-integration-testutils",
"framework-protos",
"mockito-target-minus-junit4",
"net-tests-utils",
"platform-test-annotations",
"service-connectivity-pre-jarjar",
"services.core",
"services.net",
],
libs: [
"android.net.ipsec.ike.stubs.module_lib",
"android.test.runner",
"android.test.base",
"android.test.mock",
"ServiceConnectivityResources",
],
jni_libs: [
"libservice-connectivity",
],
}

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.tests.net">
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
<uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
<uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.NETWORK_STACK" />
<uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.NETWORK_FACTORY" />
<uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
<uses-permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE" />
<application>
<uses-library android:name="android.test.runner" />
<uses-library android:name="android.net.ipsec.ike" />
</application>
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.frameworks.tests.net"
android:label="Frameworks Networking Tests" />
</manifest>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 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.
-->
<configuration description="Runs Frameworks Networking Tests.">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="FrameworksNetTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<option name="test-tag" value="FrameworksNetTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.frameworks.tests.net" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>

View File

@@ -0,0 +1,2 @@
# Module library in frameworks/libs/net
rule com.android.net.module.util.** android.net.frameworktests.util.@1

View File

@@ -0,0 +1,212 @@
/*
* Copyright (C) 2018 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 android.app.usage;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.net.ConnectivityManager;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
import android.net.NetworkStats.Entry;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.os.RemoteException;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkStatsManagerTest {
private @Mock INetworkStatsService mService;
private @Mock INetworkStatsSession mStatsSession;
private NetworkStatsManager mManager;
// TODO: change to NetworkTemplate.MATCH_MOBILE once internal constant rename is merged to aosp.
private static final int MATCH_MOBILE_ALL = 1;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mManager = new NetworkStatsManager(InstrumentationRegistry.getContext(), mService);
}
@Test
public void testQueryDetails() throws RemoteException {
final String subscriberId = "subid";
final long startTime = 1;
final long endTime = 100;
final int uid1 = 10001;
final int uid2 = 10002;
final int uid3 = 10003;
Entry uid1Entry1 = new Entry("if1", uid1,
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
100, 10, 200, 20, 0);
Entry uid1Entry2 = new Entry(
"if2", uid1,
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
100, 10, 200, 20, 0);
Entry uid2Entry1 = new Entry("if1", uid2,
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
150, 10, 250, 20, 0);
Entry uid2Entry2 = new Entry(
"if2", uid2,
android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
150, 10, 250, 20, 0);
NetworkStatsHistory history1 = new NetworkStatsHistory(10, 2);
history1.recordData(10, 20, uid1Entry1);
history1.recordData(20, 30, uid1Entry2);
NetworkStatsHistory history2 = new NetworkStatsHistory(10, 2);
history1.recordData(30, 40, uid2Entry1);
history1.recordData(35, 45, uid2Entry2);
when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2, uid3 });
when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
eq(uid1), eq(android.net.NetworkStats.SET_ALL),
eq(android.net.NetworkStats.TAG_NONE),
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
.then((InvocationOnMock inv) -> {
NetworkTemplate template = inv.getArgument(0);
assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
assertEquals(subscriberId, template.getSubscriberId());
return history1;
});
when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
eq(uid2), eq(android.net.NetworkStats.SET_ALL),
eq(android.net.NetworkStats.TAG_NONE),
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
.then((InvocationOnMock inv) -> {
NetworkTemplate template = inv.getArgument(0);
assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
assertEquals(subscriberId, template.getSubscriberId());
return history2;
});
NetworkStats stats = mManager.queryDetails(
ConnectivityManager.TYPE_MOBILE, subscriberId, startTime, endTime);
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
// First 2 buckets exactly match entry timings
assertTrue(stats.getNextBucket(bucket));
assertEquals(10, bucket.getStartTimeStamp());
assertEquals(20, bucket.getEndTimeStamp());
assertBucketMatches(uid1Entry1, bucket);
assertTrue(stats.getNextBucket(bucket));
assertEquals(20, bucket.getStartTimeStamp());
assertEquals(30, bucket.getEndTimeStamp());
assertBucketMatches(uid1Entry2, bucket);
// 30 -> 40: contains uid2Entry1 and half of uid2Entry2
assertTrue(stats.getNextBucket(bucket));
assertEquals(30, bucket.getStartTimeStamp());
assertEquals(40, bucket.getEndTimeStamp());
assertEquals(225, bucket.getRxBytes());
assertEquals(15, bucket.getRxPackets());
assertEquals(375, bucket.getTxBytes());
assertEquals(30, bucket.getTxPackets());
// 40 -> 50: contains half of uid2Entry2
assertTrue(stats.getNextBucket(bucket));
assertEquals(40, bucket.getStartTimeStamp());
assertEquals(50, bucket.getEndTimeStamp());
assertEquals(75, bucket.getRxBytes());
assertEquals(5, bucket.getRxPackets());
assertEquals(125, bucket.getTxBytes());
assertEquals(10, bucket.getTxPackets());
assertFalse(stats.hasNextBucket());
}
@Test
public void testQueryDetails_NoSubscriberId() throws RemoteException {
final long startTime = 1;
final long endTime = 100;
final int uid1 = 10001;
final int uid2 = 10002;
when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2 });
NetworkStats stats = mManager.queryDetails(
ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);
when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()))
.thenReturn(new NetworkStatsHistory(10, 0));
verify(mStatsSession, times(1)).getHistoryIntervalForUid(
argThat((NetworkTemplate t) ->
// No subscriberId: MATCH_MOBILE_WILDCARD template
t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
eq(uid1), eq(android.net.NetworkStats.SET_ALL),
eq(android.net.NetworkStats.TAG_NONE),
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
verify(mStatsSession, times(1)).getHistoryIntervalForUid(
argThat((NetworkTemplate t) ->
// No subscriberId: MATCH_MOBILE_WILDCARD template
t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
eq(uid2), eq(android.net.NetworkStats.SET_ALL),
eq(android.net.NetworkStats.TAG_NONE),
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
assertFalse(stats.hasNextBucket());
}
private void assertBucketMatches(Entry expected, NetworkStats.Bucket actual) {
assertEquals(expected.uid, actual.getUid());
assertEquals(expected.rxBytes, actual.getRxBytes());
assertEquals(expected.rxPackets, actual.getRxPackets());
assertEquals(expected.txBytes, actual.getTxBytes());
assertEquals(expected.txPackets, actual.getTxPackets());
}
}

View File

@@ -0,0 +1,384 @@
/*
* Copyright (C) 2020 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 android.net;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsBinder;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.content.Context;
import android.os.PersistableBundle;
import androidx.test.InstrumentationRegistry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import java.util.concurrent.Executor;
@RunWith(JUnit4.class)
public class ConnectivityDiagnosticsManagerTest {
private static final int NET_ID = 1;
private static final int DETECTION_METHOD = 2;
private static final long TIMESTAMP = 10L;
private static final String INTERFACE_NAME = "interface";
private static final String BUNDLE_KEY = "key";
private static final String BUNDLE_VALUE = "value";
private static final Executor INLINE_EXECUTOR = x -> x.run();
@Mock private IConnectivityManager mService;
@Mock private ConnectivityDiagnosticsCallback mCb;
private Context mContext;
private ConnectivityDiagnosticsBinder mBinder;
private ConnectivityDiagnosticsManager mManager;
private String mPackageName;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getContext();
mService = mock(IConnectivityManager.class);
mCb = mock(ConnectivityDiagnosticsCallback.class);
mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR);
mManager = new ConnectivityDiagnosticsManager(mContext, mService);
mPackageName = mContext.getOpPackageName();
}
@After
public void tearDown() {
// clear ConnectivityDiagnosticsManager callbacks map
ConnectivityDiagnosticsManager.sCallbacks.clear();
}
private ConnectivityReport createSampleConnectivityReport() {
final LinkProperties linkProperties = new LinkProperties();
linkProperties.setInterfaceName(INTERFACE_NAME);
final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
final PersistableBundle bundle = new PersistableBundle();
bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
return new ConnectivityReport(
new Network(NET_ID), TIMESTAMP, linkProperties, networkCapabilities, bundle);
}
private ConnectivityReport createDefaultConnectivityReport() {
return new ConnectivityReport(
new Network(0),
0L,
new LinkProperties(),
new NetworkCapabilities(),
PersistableBundle.EMPTY);
}
@Test
public void testPersistableBundleEquals() {
assertFalse(
ConnectivityDiagnosticsManager.persistableBundleEquals(
null, PersistableBundle.EMPTY));
assertFalse(
ConnectivityDiagnosticsManager.persistableBundleEquals(
PersistableBundle.EMPTY, null));
assertTrue(
ConnectivityDiagnosticsManager.persistableBundleEquals(
PersistableBundle.EMPTY, PersistableBundle.EMPTY));
final PersistableBundle a = new PersistableBundle();
a.putString(BUNDLE_KEY, BUNDLE_VALUE);
final PersistableBundle b = new PersistableBundle();
b.putString(BUNDLE_KEY, BUNDLE_VALUE);
final PersistableBundle c = new PersistableBundle();
c.putString(BUNDLE_KEY, null);
assertFalse(
ConnectivityDiagnosticsManager.persistableBundleEquals(PersistableBundle.EMPTY, a));
assertFalse(
ConnectivityDiagnosticsManager.persistableBundleEquals(a, PersistableBundle.EMPTY));
assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(a, b));
assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(b, a));
assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(a, c));
assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(c, a));
}
@Test
public void testConnectivityReportEquals() {
final ConnectivityReport defaultReport = createDefaultConnectivityReport();
final ConnectivityReport sampleReport = createSampleConnectivityReport();
assertEquals(sampleReport, createSampleConnectivityReport());
assertEquals(defaultReport, createDefaultConnectivityReport());
final LinkProperties linkProperties = sampleReport.getLinkProperties();
final NetworkCapabilities networkCapabilities = sampleReport.getNetworkCapabilities();
final PersistableBundle bundle = sampleReport.getAdditionalInfo();
assertNotEquals(
createDefaultConnectivityReport(),
new ConnectivityReport(
new Network(NET_ID),
0L,
new LinkProperties(),
new NetworkCapabilities(),
PersistableBundle.EMPTY));
assertNotEquals(
createDefaultConnectivityReport(),
new ConnectivityReport(
new Network(0),
TIMESTAMP,
new LinkProperties(),
new NetworkCapabilities(),
PersistableBundle.EMPTY));
assertNotEquals(
createDefaultConnectivityReport(),
new ConnectivityReport(
new Network(0),
0L,
linkProperties,
new NetworkCapabilities(),
PersistableBundle.EMPTY));
assertNotEquals(
createDefaultConnectivityReport(),
new ConnectivityReport(
new Network(0),
TIMESTAMP,
new LinkProperties(),
networkCapabilities,
PersistableBundle.EMPTY));
assertNotEquals(
createDefaultConnectivityReport(),
new ConnectivityReport(
new Network(0),
TIMESTAMP,
new LinkProperties(),
new NetworkCapabilities(),
bundle));
}
@Test
public void testConnectivityReportParcelUnparcel() {
assertParcelSane(createSampleConnectivityReport(), 5);
}
private DataStallReport createSampleDataStallReport() {
final LinkProperties linkProperties = new LinkProperties();
linkProperties.setInterfaceName(INTERFACE_NAME);
final PersistableBundle bundle = new PersistableBundle();
bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
return new DataStallReport(
new Network(NET_ID),
TIMESTAMP,
DETECTION_METHOD,
linkProperties,
networkCapabilities,
bundle);
}
private DataStallReport createDefaultDataStallReport() {
return new DataStallReport(
new Network(0),
0L,
0,
new LinkProperties(),
new NetworkCapabilities(),
PersistableBundle.EMPTY);
}
@Test
public void testDataStallReportEquals() {
final DataStallReport defaultReport = createDefaultDataStallReport();
final DataStallReport sampleReport = createSampleDataStallReport();
assertEquals(sampleReport, createSampleDataStallReport());
assertEquals(defaultReport, createDefaultDataStallReport());
final LinkProperties linkProperties = sampleReport.getLinkProperties();
final NetworkCapabilities networkCapabilities = sampleReport.getNetworkCapabilities();
final PersistableBundle bundle = sampleReport.getStallDetails();
assertNotEquals(
defaultReport,
new DataStallReport(
new Network(NET_ID),
0L,
0,
new LinkProperties(),
new NetworkCapabilities(),
PersistableBundle.EMPTY));
assertNotEquals(
defaultReport,
new DataStallReport(
new Network(0),
TIMESTAMP,
0,
new LinkProperties(),
new NetworkCapabilities(),
PersistableBundle.EMPTY));
assertNotEquals(
defaultReport,
new DataStallReport(
new Network(0),
0L,
DETECTION_METHOD,
new LinkProperties(),
new NetworkCapabilities(),
PersistableBundle.EMPTY));
assertNotEquals(
defaultReport,
new DataStallReport(
new Network(0),
0L,
0,
linkProperties,
new NetworkCapabilities(),
PersistableBundle.EMPTY));
assertNotEquals(
defaultReport,
new DataStallReport(
new Network(0),
0L,
0,
new LinkProperties(),
networkCapabilities,
PersistableBundle.EMPTY));
assertNotEquals(
defaultReport,
new DataStallReport(
new Network(0),
0L,
0,
new LinkProperties(),
new NetworkCapabilities(),
bundle));
}
@Test
public void testDataStallReportParcelUnparcel() {
assertParcelSane(createSampleDataStallReport(), 6);
}
@Test
public void testConnectivityDiagnosticsCallbackOnConnectivityReportAvailable() {
mBinder.onConnectivityReportAvailable(createSampleConnectivityReport());
// The callback will be invoked synchronously by inline executor. Immediately check the
// latch without waiting.
verify(mCb).onConnectivityReportAvailable(eq(createSampleConnectivityReport()));
}
@Test
public void testConnectivityDiagnosticsCallbackOnDataStallSuspected() {
mBinder.onDataStallSuspected(createSampleDataStallReport());
// The callback will be invoked synchronously by inline executor. Immediately check the
// latch without waiting.
verify(mCb).onDataStallSuspected(eq(createSampleDataStallReport()));
}
@Test
public void testConnectivityDiagnosticsCallbackOnNetworkConnectivityReported() {
final Network n = new Network(NET_ID);
final boolean connectivity = true;
mBinder.onNetworkConnectivityReported(n, connectivity);
// The callback will be invoked synchronously by inline executor. Immediately check the
// latch without waiting.
verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity));
}
@Test
public void testRegisterConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest request = new NetworkRequest.Builder().build();
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
verify(mService).registerConnectivityDiagnosticsCallback(
any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName));
assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
}
@Test
public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest request = new NetworkRequest.Builder().build();
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
try {
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
fail("Duplicate callback registration should fail");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testUnregisterConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest request = new NetworkRequest.Builder().build();
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
mManager.unregisterConnectivityDiagnosticsCallback(mCb);
verify(mService).unregisterConnectivityDiagnosticsCallback(
any(ConnectivityDiagnosticsBinder.class));
assertFalse(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
// verify that re-registering is successful
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
verify(mService, times(2)).registerConnectivityDiagnosticsCallback(
any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName));
assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
}
@Test
public void testUnregisterUnknownConnectivityDiagnosticsCallback() throws Exception {
mManager.unregisterConnectivityDiagnosticsCallback(mCb);
verifyNoMoreInteractions(mService);
}
}

View File

@@ -0,0 +1,430 @@
/*
* Copyright (C) 2017 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 android.net;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
import static android.net.NetworkRequest.Type.REQUEST;
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.Process;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ConnectivityManagerTest {
@Mock Context mCtx;
@Mock IConnectivityManager mService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
static NetworkCapabilities verifyNetworkCapabilities(
int legacyType, int transportType, int... capabilities) {
final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
assertNotNull(nc);
assertTrue(nc.hasTransport(transportType));
for (int capability : capabilities) {
assertTrue(nc.hasCapability(capability));
}
return nc;
}
static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) {
verifyNetworkCapabilities(
legacyType,
transportType,
NET_CAPABILITY_INTERNET,
NET_CAPABILITY_NOT_RESTRICTED,
NET_CAPABILITY_NOT_VPN,
NET_CAPABILITY_TRUSTED);
}
static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) {
final NetworkCapabilities nc = verifyNetworkCapabilities(
legacyType,
TRANSPORT_CELLULAR,
capability,
NET_CAPABILITY_NOT_VPN,
NET_CAPABILITY_TRUSTED);
assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
}
@Test
public void testNetworkCapabilitiesForTypeMobile() {
verifyUnrestrictedNetworkCapabilities(
ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR);
}
@Test
public void testNetworkCapabilitiesForTypeMobileCbs() {
verifyRestrictedMobileNetworkCapabilities(
ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS);
}
@Test
public void testNetworkCapabilitiesForTypeMobileDun() {
verifyRestrictedMobileNetworkCapabilities(
ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN);
}
@Test
public void testNetworkCapabilitiesForTypeMobileFota() {
verifyRestrictedMobileNetworkCapabilities(
ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA);
}
@Test
public void testNetworkCapabilitiesForTypeMobileHipri() {
verifyUnrestrictedNetworkCapabilities(
ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR);
}
@Test
public void testNetworkCapabilitiesForTypeMobileIms() {
verifyRestrictedMobileNetworkCapabilities(
ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS);
}
@Test
public void testNetworkCapabilitiesForTypeMobileMms() {
final NetworkCapabilities nc = verifyNetworkCapabilities(
ConnectivityManager.TYPE_MOBILE_MMS,
TRANSPORT_CELLULAR,
NET_CAPABILITY_MMS,
NET_CAPABILITY_NOT_VPN,
NET_CAPABILITY_TRUSTED);
assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
}
@Test
public void testNetworkCapabilitiesForTypeMobileSupl() {
final NetworkCapabilities nc = verifyNetworkCapabilities(
ConnectivityManager.TYPE_MOBILE_SUPL,
TRANSPORT_CELLULAR,
NET_CAPABILITY_SUPL,
NET_CAPABILITY_NOT_VPN,
NET_CAPABILITY_TRUSTED);
assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
}
@Test
public void testNetworkCapabilitiesForTypeWifi() {
verifyUnrestrictedNetworkCapabilities(
ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI);
}
@Test
public void testNetworkCapabilitiesForTypeWifiP2p() {
final NetworkCapabilities nc = verifyNetworkCapabilities(
ConnectivityManager.TYPE_WIFI_P2P,
TRANSPORT_WIFI,
NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN,
NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P);
assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
}
@Test
public void testNetworkCapabilitiesForTypeBluetooth() {
verifyUnrestrictedNetworkCapabilities(
ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH);
}
@Test
public void testNetworkCapabilitiesForTypeEthernet() {
verifyUnrestrictedNetworkCapabilities(
ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET);
}
@Test
public void testCallbackRelease() throws Exception {
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
NetworkRequest request = makeRequest(1);
NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
Handler handler = new Handler(Looper.getMainLooper());
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(request);
manager.requestNetwork(request, callback, handler);
// callback triggers
captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE));
verify(callback, timeout(500).times(1)).onAvailable(any(Network.class),
any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
// unregister callback
manager.unregisterNetworkCallback(callback);
verify(mService, times(1)).releaseNetworkRequest(request);
// callback does not trigger anymore.
captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_LOSING));
verify(callback, timeout(500).times(0)).onLosing(any(), anyInt());
}
@Test
public void testCallbackRecycling() throws Exception {
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
NetworkRequest req1 = makeRequest(1);
NetworkRequest req2 = makeRequest(2);
NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
Handler handler = new Handler(Looper.getMainLooper());
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req1);
manager.requestNetwork(req1, callback, handler);
// callback triggers
captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE));
verify(callback, timeout(100).times(1)).onAvailable(any(Network.class),
any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
// unregister callback
manager.unregisterNetworkCallback(callback);
verify(mService, times(1)).releaseNetworkRequest(req1);
// callback does not trigger anymore.
captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_LOSING));
verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
// callback can be registered again
when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req2);
manager.requestNetwork(req2, callback, handler);
// callback triggers
captor.getValue().send(makeMessage(req2, ConnectivityManager.CALLBACK_LOST));
verify(callback, timeout(100).times(1)).onLost(any());
// unregister callback
manager.unregisterNetworkCallback(callback);
verify(mService, times(1)).releaseNetworkRequest(req2);
}
// TODO: turn on this test when request callback 1:1 mapping is enforced
//@Test
private void noDoubleCallbackRegistration() throws Exception {
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
NetworkRequest request = makeRequest(1);
NetworkCallback callback = new ConnectivityManager.NetworkCallback();
ApplicationInfo info = new ApplicationInfo();
// TODO: update version when starting to enforce 1:1 mapping
info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
when(mCtx.getApplicationInfo()).thenReturn(info);
when(mService.requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(),
anyInt(), any(), nullable(String.class))).thenReturn(request);
Handler handler = new Handler(Looper.getMainLooper());
manager.requestNetwork(request, callback, handler);
// callback is already registered, reregistration should fail.
Class<IllegalArgumentException> wantException = IllegalArgumentException.class;
expectThrowable(() -> manager.requestNetwork(request, callback), wantException);
manager.unregisterNetworkCallback(callback);
verify(mService, times(1)).releaseNetworkRequest(request);
// unregistering the callback should make it registrable again.
manager.requestNetwork(request, callback);
}
@Test
public void testArgumentValidation() throws Exception {
ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
NetworkRequest request = mock(NetworkRequest.class);
NetworkCallback callback = mock(NetworkCallback.class);
Handler handler = mock(Handler.class);
NetworkCallback nullCallback = null;
PendingIntent nullIntent = null;
mustFail(() -> { manager.requestNetwork(null, callback); });
mustFail(() -> { manager.requestNetwork(request, nullCallback); });
mustFail(() -> { manager.requestNetwork(request, callback, null); });
mustFail(() -> { manager.requestNetwork(request, callback, -1); });
mustFail(() -> { manager.requestNetwork(request, nullIntent); });
mustFail(() -> { manager.registerNetworkCallback(null, callback, handler); });
mustFail(() -> { manager.registerNetworkCallback(request, null, handler); });
mustFail(() -> { manager.registerNetworkCallback(request, callback, null); });
mustFail(() -> { manager.registerNetworkCallback(request, nullIntent); });
mustFail(() -> { manager.registerDefaultNetworkCallback(null, handler); });
mustFail(() -> { manager.registerDefaultNetworkCallback(callback, null); });
mustFail(() -> { manager.registerSystemDefaultNetworkCallback(null, handler); });
mustFail(() -> { manager.registerSystemDefaultNetworkCallback(callback, null); });
mustFail(() -> { manager.unregisterNetworkCallback(nullCallback); });
mustFail(() -> { manager.unregisterNetworkCallback(nullIntent); });
mustFail(() -> { manager.releaseNetworkRequest(nullIntent); });
}
static void mustFail(Runnable fn) {
try {
fn.run();
fail();
} catch (Exception expected) {
}
}
@Test
public void testRequestType() throws Exception {
final String testPkgName = "MyPackage";
final String testAttributionTag = "MyTag";
final ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
when(mCtx.getOpPackageName()).thenReturn(testPkgName);
when(mCtx.getAttributionTag()).thenReturn(testAttributionTag);
final NetworkRequest request = makeRequest(1);
final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
manager.requestNetwork(request, callback);
verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
// Verify that register network callback does not calls requestNetwork at all.
manager.registerNetworkCallback(request, callback);
verify(mService, never()).requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(),
anyInt(), anyInt(), any(), any());
verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
manager.registerDefaultNetworkCallback(callback);
verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.registerDefaultNetworkCallbackForUid(42, callback, handler);
verify(mService).requestNetwork(eq(42), eq(null),
eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
manager.requestBackgroundNetwork(request, callback, handler);
verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.registerSystemDefaultNetworkCallback(callback, handler);
verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
}
static Message makeMessage(NetworkRequest req, int messageType) {
Bundle bundle = new Bundle();
bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
// Pass default objects as we don't care which get passed here
bundle.putParcelable(Network.class.getSimpleName(), new Network(1));
bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities());
bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties());
Message msg = Message.obtain();
msg.what = messageType;
msg.setData(bundle);
return msg;
}
static NetworkRequest makeRequest(int requestId) {
NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
return new NetworkRequest(request.networkCapabilities, ConnectivityManager.TYPE_NONE,
requestId, NetworkRequest.Type.NONE);
}
static void expectThrowable(Runnable block, Class<? extends Throwable> throwableType) {
try {
block.run();
} catch (Throwable t) {
if (t.getClass().equals(throwableType)) {
return;
}
fail("expected exception of type " + throwableType + ", but was " + t.getClass());
}
fail("expected exception of type " + throwableType);
}
}

View File

@@ -0,0 +1,439 @@
/*
* Copyright (C) 2019 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 android.net;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.test.mock.MockContext;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.net.VpnProfile;
import com.android.net.module.util.ProxyUtils;
import com.android.internal.org.bouncycastle.x509.X509V1CertificateGenerator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.security.auth.x500.X500Principal;
/** Unit tests for {@link Ikev2VpnProfile.Builder}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class Ikev2VpnProfileTest {
private static final String SERVER_ADDR_STRING = "1.2.3.4";
private static final String IDENTITY_STRING = "Identity";
private static final String USERNAME_STRING = "username";
private static final String PASSWORD_STRING = "pa55w0rd";
private static final String EXCL_LIST = "exclList";
private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
private static final int TEST_MTU = 1300;
private final MockContext mMockContext =
new MockContext() {
@Override
public String getOpPackageName() {
return "fooPackage";
}
};
private final ProxyInfo mProxy = ProxyInfo.buildDirectProxy(
SERVER_ADDR_STRING, -1, ProxyUtils.exclusionStringAsList(EXCL_LIST));
private X509Certificate mUserCert;
private X509Certificate mServerRootCa;
private PrivateKey mPrivateKey;
@Before
public void setUp() throws Exception {
mServerRootCa = generateRandomCertAndKeyPair().cert;
final CertificateAndKey userCertKey = generateRandomCertAndKeyPair();
mUserCert = userCertKey.cert;
mPrivateKey = userCertKey.key;
}
private Ikev2VpnProfile.Builder getBuilderWithDefaultOptions() {
final Ikev2VpnProfile.Builder builder =
new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING);
builder.setBypassable(true);
builder.setProxy(mProxy);
builder.setMaxMtu(TEST_MTU);
builder.setMetered(true);
return builder;
}
@Test
public void testBuildValidProfileWithOptions() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
final Ikev2VpnProfile profile = builder.build();
assertNotNull(profile);
// Check non-auth parameters correctly stored
assertEquals(SERVER_ADDR_STRING, profile.getServerAddr());
assertEquals(IDENTITY_STRING, profile.getUserIdentity());
assertEquals(mProxy, profile.getProxyInfo());
assertTrue(profile.isBypassable());
assertTrue(profile.isMetered());
assertEquals(TEST_MTU, profile.getMaxMtu());
assertEquals(Ikev2VpnProfile.DEFAULT_ALGORITHMS, profile.getAllowedAlgorithms());
}
@Test
public void testBuildUsernamePasswordProfile() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
final Ikev2VpnProfile profile = builder.build();
assertNotNull(profile);
assertEquals(USERNAME_STRING, profile.getUsername());
assertEquals(PASSWORD_STRING, profile.getPassword());
assertEquals(mServerRootCa, profile.getServerRootCaCert());
assertNull(profile.getPresharedKey());
assertNull(profile.getRsaPrivateKey());
assertNull(profile.getUserCert());
}
@Test
public void testBuildDigitalSignatureProfile() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
final Ikev2VpnProfile profile = builder.build();
assertNotNull(profile);
assertEquals(profile.getUserCert(), mUserCert);
assertEquals(mPrivateKey, profile.getRsaPrivateKey());
assertEquals(profile.getServerRootCaCert(), mServerRootCa);
assertNull(profile.getPresharedKey());
assertNull(profile.getUsername());
assertNull(profile.getPassword());
}
@Test
public void testBuildPresharedKeyProfile() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthPsk(PSK_BYTES);
final Ikev2VpnProfile profile = builder.build();
assertNotNull(profile);
assertArrayEquals(PSK_BYTES, profile.getPresharedKey());
assertNull(profile.getServerRootCaCert());
assertNull(profile.getUsername());
assertNull(profile.getPassword());
assertNull(profile.getRsaPrivateKey());
assertNull(profile.getUserCert());
}
@Test
public void testBuildWithAllowedAlgorithmsAead() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthPsk(PSK_BYTES);
List<String> allowedAlgorithms = Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
builder.setAllowedAlgorithms(allowedAlgorithms);
final Ikev2VpnProfile profile = builder.build();
assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
}
@Test
public void testBuildWithAllowedAlgorithmsNormal() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthPsk(PSK_BYTES);
List<String> allowedAlgorithms =
Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA512, IpSecAlgorithm.CRYPT_AES_CBC);
builder.setAllowedAlgorithms(allowedAlgorithms);
final Ikev2VpnProfile profile = builder.build();
assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
}
@Test
public void testSetAllowedAlgorithmsEmptyList() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
try {
builder.setAllowedAlgorithms(new ArrayList<>());
fail("Expected exception due to no valid algorithm set");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testSetAllowedAlgorithmsInvalidList() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
List<String> allowedAlgorithms = new ArrayList<>();
try {
builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA256));
fail("Expected exception due to missing encryption");
} catch (IllegalArgumentException expected) {
}
try {
builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.CRYPT_AES_CBC));
fail("Expected exception due to missing authentication");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testSetAllowedAlgorithmsInsecureAlgorithm() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
List<String> allowedAlgorithms = new ArrayList<>();
try {
builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_MD5));
fail("Expected exception due to insecure algorithm");
} catch (IllegalArgumentException expected) {
}
try {
builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA1));
fail("Expected exception due to insecure algorithm");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testBuildNoAuthMethodSet() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
try {
builder.build();
fail("Expected exception due to lack of auth method");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testBuildInvalidMtu() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
try {
builder.setMaxMtu(500);
fail("Expected exception due to too-small MTU");
} catch (IllegalArgumentException expected) {
}
}
private void verifyVpnProfileCommon(VpnProfile profile) {
assertEquals(SERVER_ADDR_STRING, profile.server);
assertEquals(IDENTITY_STRING, profile.ipsecIdentifier);
assertEquals(mProxy, profile.proxy);
assertTrue(profile.isBypassable);
assertTrue(profile.isMetered);
assertEquals(TEST_MTU, profile.maxMtu);
}
@Test
public void testPskConvertToVpnProfile() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthPsk(PSK_BYTES);
final VpnProfile profile = builder.build().toVpnProfile();
verifyVpnProfileCommon(profile);
assertEquals(Ikev2VpnProfile.encodeForIpsecSecret(PSK_BYTES), profile.ipsecSecret);
// Check nothing else is set
assertEquals("", profile.username);
assertEquals("", profile.password);
assertEquals("", profile.ipsecUserCert);
assertEquals("", profile.ipsecCaCert);
}
@Test
public void testUsernamePasswordConvertToVpnProfile() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
final VpnProfile profile = builder.build().toVpnProfile();
verifyVpnProfileCommon(profile);
assertEquals(USERNAME_STRING, profile.username);
assertEquals(PASSWORD_STRING, profile.password);
assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
// Check nothing else is set
assertEquals("", profile.ipsecUserCert);
assertEquals("", profile.ipsecSecret);
}
@Test
public void testRsaConvertToVpnProfile() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
final VpnProfile profile = builder.build().toVpnProfile();
final String expectedSecret = Ikev2VpnProfile.PREFIX_INLINE
+ Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded());
verifyVpnProfileCommon(profile);
assertEquals(Ikev2VpnProfile.certificateToPemString(mUserCert), profile.ipsecUserCert);
assertEquals(
expectedSecret,
profile.ipsecSecret);
assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
// Check nothing else is set
assertEquals("", profile.username);
assertEquals("", profile.password);
}
@Test
public void testPskFromVpnProfileDiscardsIrrelevantValues() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthPsk(PSK_BYTES);
final VpnProfile profile = builder.build().toVpnProfile();
profile.username = USERNAME_STRING;
profile.password = PASSWORD_STRING;
profile.ipsecCaCert = Ikev2VpnProfile.certificateToPemString(mServerRootCa);
profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
assertNull(result.getUsername());
assertNull(result.getPassword());
assertNull(result.getUserCert());
assertNull(result.getRsaPrivateKey());
assertNull(result.getServerRootCaCert());
}
@Test
public void testUsernamePasswordFromVpnProfileDiscardsIrrelevantValues() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
final VpnProfile profile = builder.build().toVpnProfile();
profile.ipsecSecret = new String(PSK_BYTES);
profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
assertNull(result.getPresharedKey());
assertNull(result.getUserCert());
assertNull(result.getRsaPrivateKey());
}
@Test
public void testRsaFromVpnProfileDiscardsIrrelevantValues() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
final VpnProfile profile = builder.build().toVpnProfile();
profile.username = USERNAME_STRING;
profile.password = PASSWORD_STRING;
final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
assertNull(result.getUsername());
assertNull(result.getPassword());
assertNull(result.getPresharedKey());
}
@Test
public void testPskConversionIsLossless() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthPsk(PSK_BYTES);
final Ikev2VpnProfile ikeProfile = builder.build();
assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
}
@Test
public void testUsernamePasswordConversionIsLossless() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
final Ikev2VpnProfile ikeProfile = builder.build();
assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
}
@Test
public void testRsaConversionIsLossless() throws Exception {
final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
final Ikev2VpnProfile ikeProfile = builder.build();
assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
}
private static class CertificateAndKey {
public final X509Certificate cert;
public final PrivateKey key;
CertificateAndKey(X509Certificate cert, PrivateKey key) {
this.cert = cert;
this.key = key;
}
}
private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception {
final Date validityBeginDate =
new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L));
final Date validityEndDate =
new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L));
// Generate a keypair
final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(512);
final KeyPair keyPair = keyPairGenerator.generateKeyPair();
final X500Principal dnName = new X500Principal("CN=test.android.com");
final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setSubjectDN(dnName);
certGen.setIssuerDN(dnName);
certGen.setNotBefore(validityBeginDate);
certGen.setNotAfter(validityEndDate);
certGen.setPublicKey(keyPair.getPublic());
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL");
return new CertificateAndKey(cert, keyPair.getPrivate());
}
}

View File

@@ -0,0 +1,332 @@
/*
* Copyright (C) 2018 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 android.net;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.net.ipmemorystore.Blob;
import android.net.ipmemorystore.IOnStatusListener;
import android.net.ipmemorystore.NetworkAttributes;
import android.net.ipmemorystore.NetworkAttributesParcelable;
import android.net.ipmemorystore.Status;
import android.net.networkstack.ModuleNetworkStackClient;
import android.os.RemoteException;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.net.UnknownHostException;
import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class IpMemoryStoreTest {
private static final String TAG = IpMemoryStoreTest.class.getSimpleName();
private static final String TEST_CLIENT_ID = "testClientId";
private static final String TEST_DATA_NAME = "testData";
private static final String TEST_OTHER_DATA_NAME = TEST_DATA_NAME + "Other";
private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12,
-128, 0, 89, 112, 91, -34 };
private static final NetworkAttributes TEST_NETWORK_ATTRIBUTES = buildTestNetworkAttributes(
"hint", 219);
@Mock
Context mMockContext;
@Mock
ModuleNetworkStackClient mModuleNetworkStackClient;
@Mock
IIpMemoryStore mMockService;
@Mock
IOnStatusListener mIOnStatusListener;
IpMemoryStore mStore;
@Captor
ArgumentCaptor<IIpMemoryStoreCallbacks> mCbCaptor;
@Captor
ArgumentCaptor<NetworkAttributesParcelable> mNapCaptor;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
private void startIpMemoryStore(boolean supplyService) {
if (supplyService) {
doAnswer(invocation -> {
((IIpMemoryStoreCallbacks) invocation.getArgument(0))
.onIpMemoryStoreFetched(mMockService);
return null;
}).when(mModuleNetworkStackClient).fetchIpMemoryStore(any());
} else {
doNothing().when(mModuleNetworkStackClient).fetchIpMemoryStore(mCbCaptor.capture());
}
mStore = new IpMemoryStore(mMockContext) {
@Override
protected ModuleNetworkStackClient getModuleNetworkStackClient(Context ctx) {
return mModuleNetworkStackClient;
}
};
}
private static NetworkAttributes buildTestNetworkAttributes(String hint, int mtu) {
return new NetworkAttributes.Builder()
.setCluster(hint)
.setMtu(mtu)
.build();
}
@Test
public void testNetworkAttributes() throws Exception {
startIpMemoryStore(true /* supplyService */);
final String l2Key = "fakeKey";
mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
status -> assertTrue("Store not successful : " + status.resultCode,
status.isSuccess()));
verify(mMockService, times(1)).storeNetworkAttributes(eq(l2Key),
mNapCaptor.capture(), any());
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
mStore.retrieveNetworkAttributes(l2Key,
(status, key, attr) -> {
assertTrue("Retrieve network attributes not successful : "
+ status.resultCode, status.isSuccess());
assertEquals(l2Key, key);
assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
});
verify(mMockService, times(1)).retrieveNetworkAttributes(eq(l2Key), any());
}
@Test
public void testPrivateData() throws RemoteException {
startIpMemoryStore(true /* supplyService */);
final Blob b = new Blob();
b.data = TEST_BLOB_DATA;
final String l2Key = "fakeKey";
mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
status -> {
assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
});
verify(mMockService, times(1)).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
eq(b), any());
mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
(status, key, name, data) -> {
assertTrue("Retrieve blob status not successful : " + status.resultCode,
status.isSuccess());
assertEquals(l2Key, key);
assertEquals(name, TEST_DATA_NAME);
assertTrue(Arrays.equals(b.data, data.data));
});
verify(mMockService, times(1)).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
eq(TEST_OTHER_DATA_NAME), any());
}
@Test
public void testFindL2Key()
throws UnknownHostException, RemoteException, Exception {
startIpMemoryStore(true /* supplyService */);
final String l2Key = "fakeKey";
mStore.findL2Key(TEST_NETWORK_ATTRIBUTES,
(status, key) -> {
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
status.isSuccess());
assertEquals(l2Key, key);
});
verify(mMockService, times(1)).findL2Key(mNapCaptor.capture(), any());
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
}
@Test
public void testIsSameNetwork() throws UnknownHostException, RemoteException {
startIpMemoryStore(true /* supplyService */);
final String l2Key1 = "fakeKey1";
final String l2Key2 = "fakeKey2";
mStore.isSameNetwork(l2Key1, l2Key2,
(status, answer) -> {
assertFalse("Retrieve network sameness suspiciously successful : "
+ status.resultCode, status.isSuccess());
assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
assertNull(answer);
});
verify(mMockService, times(1)).isSameNetwork(eq(l2Key1), eq(l2Key2), any());
}
@Test
public void testEnqueuedIpMsRequests() throws Exception {
startIpMemoryStore(false /* supplyService */);
final Blob b = new Blob();
b.data = TEST_BLOB_DATA;
final String l2Key = "fakeKey";
// enqueue multiple ipms requests
mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
status -> assertTrue("Store not successful : " + status.resultCode,
status.isSuccess()));
mStore.retrieveNetworkAttributes(l2Key,
(status, key, attr) -> {
assertTrue("Retrieve network attributes not successful : "
+ status.resultCode, status.isSuccess());
assertEquals(l2Key, key);
assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
});
mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
status -> assertTrue("Store not successful : " + status.resultCode,
status.isSuccess()));
mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
(status, key, name, data) -> {
assertTrue("Retrieve blob status not successful : " + status.resultCode,
status.isSuccess());
assertEquals(l2Key, key);
assertEquals(name, TEST_DATA_NAME);
assertTrue(Arrays.equals(b.data, data.data));
});
// get ipms service ready
mCbCaptor.getValue().onIpMemoryStoreFetched(mMockService);
InOrder inOrder = inOrder(mMockService);
inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
eq(b), any());
inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
eq(TEST_OTHER_DATA_NAME), any());
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
}
@Test
public void testEnqueuedIpMsRequestsWithException() throws Exception {
startIpMemoryStore(true /* supplyService */);
doThrow(RemoteException.class).when(mMockService).retrieveNetworkAttributes(any(), any());
final Blob b = new Blob();
b.data = TEST_BLOB_DATA;
final String l2Key = "fakeKey";
// enqueue multiple ipms requests
mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
status -> assertTrue("Store not successful : " + status.resultCode,
status.isSuccess()));
mStore.retrieveNetworkAttributes(l2Key,
(status, key, attr) -> {
assertTrue("Retrieve network attributes not successful : "
+ status.resultCode, status.isSuccess());
assertEquals(l2Key, key);
assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
});
mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
status -> assertTrue("Store not successful : " + status.resultCode,
status.isSuccess()));
mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
(status, key, name, data) -> {
assertTrue("Retrieve blob status not successful : " + status.resultCode,
status.isSuccess());
assertEquals(l2Key, key);
assertEquals(name, TEST_DATA_NAME);
assertTrue(Arrays.equals(b.data, data.data));
});
// verify the rest of the queue is still processed in order even if the remote exception
// occurs when calling one or more requests
InOrder inOrder = inOrder(mMockService);
inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
eq(b), any());
inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
eq(TEST_OTHER_DATA_NAME), any());
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
}
@Test
public void testEnqueuedIpMsRequestsCallbackFunctionWithException() throws Exception {
startIpMemoryStore(true /* supplyService */);
final Blob b = new Blob();
b.data = TEST_BLOB_DATA;
final String l2Key = "fakeKey";
// enqueue multiple ipms requests
mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
status -> assertTrue("Store not successful : " + status.resultCode,
status.isSuccess()));
mStore.retrieveNetworkAttributes(l2Key,
(status, key, attr) -> {
throw new RuntimeException("retrieveNetworkAttributes test");
});
mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
status -> {
throw new RuntimeException("storeBlob test");
});
mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
(status, key, name, data) -> {
assertTrue("Retrieve blob status not successful : " + status.resultCode,
status.isSuccess());
assertEquals(l2Key, key);
assertEquals(name, TEST_DATA_NAME);
assertTrue(Arrays.equals(b.data, data.data));
});
// verify the rest of the queue is still processed in order even if when one or more
// callback throw the remote exception
InOrder inOrder = inOrder(mMockService);
inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(),
any());
inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
eq(b), any());
inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
eq(TEST_OTHER_DATA_NAME), any());
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
}
@Test
public void testFactoryReset() throws RemoteException {
startIpMemoryStore(true /* supplyService */);
mStore.factoryReset();
verify(mMockService, times(1)).factoryReset();
}
}

View File

@@ -0,0 +1,226 @@
/*
* Copyright (C) 2017 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 android.net;
import static android.net.IpSecAlgorithm.ALGO_TO_REQUIRED_FIRST_SDK;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import android.content.res.Resources;
import android.os.Build;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.CollectionUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
/** Unit tests for {@link IpSecAlgorithm}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class IpSecAlgorithmTest {
private static final byte[] KEY_MATERIAL;
private final Resources mMockResources = mock(Resources.class);
static {
KEY_MATERIAL = new byte[128];
new Random().nextBytes(KEY_MATERIAL);
};
private static byte[] generateKey(int keyLenInBits) {
return Arrays.copyOf(KEY_MATERIAL, keyLenInBits / 8);
}
@Test
public void testNoTruncLen() throws Exception {
Entry<String, Integer>[] authAndAeadList =
new Entry[] {
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_MD5, 128),
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA1, 160),
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA256, 256),
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA384, 384),
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA512, 512),
new SimpleEntry<>(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 224),
};
// Expect auth and aead algorithms to throw errors if trunclen is omitted.
for (Entry<String, Integer> algData : authAndAeadList) {
try {
new IpSecAlgorithm(
algData.getKey(), Arrays.copyOf(KEY_MATERIAL, algData.getValue() / 8));
fail("Expected exception on unprovided auth trunclen");
} catch (IllegalArgumentException expected) {
}
}
// Ensure crypt works with no truncation length supplied.
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 256 / 8));
}
private void checkAuthKeyAndTruncLenValidation(String algoName, int keyLen, int truncLen)
throws Exception {
new IpSecAlgorithm(algoName, generateKey(keyLen), truncLen);
try {
new IpSecAlgorithm(algoName, generateKey(keyLen));
fail("Expected exception on unprovided auth trunclen");
} catch (IllegalArgumentException pass) {
}
try {
new IpSecAlgorithm(algoName, generateKey(keyLen + 8), truncLen);
fail("Invalid key length not validated");
} catch (IllegalArgumentException pass) {
}
try {
new IpSecAlgorithm(algoName, generateKey(keyLen), truncLen + 1);
fail("Invalid truncation length not validated");
} catch (IllegalArgumentException pass) {
}
}
private void checkCryptKeyLenValidation(String algoName, int keyLen) throws Exception {
new IpSecAlgorithm(algoName, generateKey(keyLen));
try {
new IpSecAlgorithm(algoName, generateKey(keyLen + 8));
fail("Invalid key length not validated");
} catch (IllegalArgumentException pass) {
}
}
@Test
public void testValidationForAlgosAddedInS() throws Exception {
if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.R) {
return;
}
for (int len : new int[] {160, 224, 288}) {
checkCryptKeyLenValidation(IpSecAlgorithm.CRYPT_AES_CTR, len);
}
checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_XCBC, 128, 96);
checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_CMAC, 128, 96);
checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, 288, 128);
}
@Test
public void testTruncLenValidation() throws Exception {
for (int truncLen : new int[] {256, 512}) {
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_SHA512,
Arrays.copyOf(KEY_MATERIAL, 512 / 8),
truncLen);
}
for (int truncLen : new int[] {255, 513}) {
try {
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_SHA512,
Arrays.copyOf(KEY_MATERIAL, 512 / 8),
truncLen);
fail("Invalid truncation length not validated");
} catch (IllegalArgumentException pass) {
}
}
}
@Test
public void testLenValidation() throws Exception {
for (int len : new int[] {128, 192, 256}) {
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, len / 8));
}
try {
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 384 / 8));
fail("Invalid key length not validated");
} catch (IllegalArgumentException pass) {
}
}
@Test
public void testAlgoNameValidation() throws Exception {
try {
new IpSecAlgorithm("rot13", Arrays.copyOf(KEY_MATERIAL, 128 / 8));
fail("Invalid algorithm name not validated");
} catch (IllegalArgumentException pass) {
}
}
@Test
public void testParcelUnparcel() throws Exception {
IpSecAlgorithm init =
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_SHA512, Arrays.copyOf(KEY_MATERIAL, 512 / 8), 256);
Parcel p = Parcel.obtain();
p.setDataPosition(0);
init.writeToParcel(p, 0);
p.setDataPosition(0);
IpSecAlgorithm fin = IpSecAlgorithm.CREATOR.createFromParcel(p);
assertTrue("Parcel/Unparcel failed!", IpSecAlgorithm.equals(init, fin));
p.recycle();
}
private static Set<String> getMandatoryAlgos() {
return CollectionUtils.filter(
ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
i -> Build.VERSION.FIRST_SDK_INT >= ALGO_TO_REQUIRED_FIRST_SDK.get(i));
}
private static Set<String> getOptionalAlgos() {
return CollectionUtils.filter(
ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
i -> Build.VERSION.FIRST_SDK_INT < ALGO_TO_REQUIRED_FIRST_SDK.get(i));
}
@Test
public void testGetSupportedAlgorithms() throws Exception {
assertTrue(IpSecAlgorithm.getSupportedAlgorithms().containsAll(getMandatoryAlgos()));
assertTrue(ALGO_TO_REQUIRED_FIRST_SDK.keySet().containsAll(
IpSecAlgorithm.getSupportedAlgorithms()));
}
@Test
public void testLoadAlgos() throws Exception {
final Set<String> optionalAlgoSet = getOptionalAlgos();
final String[] optionalAlgos = optionalAlgoSet.toArray(new String[0]);
doReturn(optionalAlgos).when(mMockResources)
.getStringArray(com.android.internal.R.array.config_optionalIpSecAlgorithms);
final Set<String> enabledAlgos = new HashSet<>(IpSecAlgorithm.loadAlgos(mMockResources));
final Set<String> expectedAlgos = ALGO_TO_REQUIRED_FIRST_SDK.keySet();
assertEquals(expectedAlgos, enabledAlgos);
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2017 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 android.net;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link IpSecConfig}. */
@SmallTest
@RunWith(JUnit4.class)
public class IpSecConfigTest {
@Test
public void testDefaults() throws Exception {
IpSecConfig c = new IpSecConfig();
assertEquals(IpSecTransform.MODE_TRANSPORT, c.getMode());
assertEquals("", c.getSourceAddress());
assertEquals("", c.getDestinationAddress());
assertNull(c.getNetwork());
assertEquals(IpSecTransform.ENCAP_NONE, c.getEncapType());
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getEncapSocketResourceId());
assertEquals(0, c.getEncapRemotePort());
assertEquals(0, c.getNattKeepaliveInterval());
assertNull(c.getEncryption());
assertNull(c.getAuthentication());
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
assertEquals(0, c.getXfrmInterfaceId());
}
private IpSecConfig getSampleConfig() {
IpSecConfig c = new IpSecConfig();
c.setMode(IpSecTransform.MODE_TUNNEL);
c.setSourceAddress("0.0.0.0");
c.setDestinationAddress("1.2.3.4");
c.setSpiResourceId(1984);
c.setEncryption(
new IpSecAlgorithm(
IpSecAlgorithm.CRYPT_AES_CBC,
new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}));
c.setAuthentication(
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_MD5,
new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0},
128));
c.setAuthenticatedEncryption(
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
new byte[] {
1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0, 1, 2, 3, 4
},
128));
c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
c.setEncapSocketResourceId(7);
c.setEncapRemotePort(22);
c.setNattKeepaliveInterval(42);
c.setMarkValue(12);
c.setMarkMask(23);
c.setXfrmInterfaceId(34);
return c;
}
@Test
public void testCopyConstructor() {
IpSecConfig original = getSampleConfig();
IpSecConfig copy = new IpSecConfig(original);
assertEquals(original, copy);
assertNotSame(original, copy);
}
@Test
public void testParcelUnparcel() {
assertParcelingIsLossless(new IpSecConfig());
IpSecConfig c = getSampleConfig();
assertParcelSane(c, 15);
}
}

View File

@@ -0,0 +1,305 @@
/*
* Copyright (C) 2017 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 android.net;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_DGRAM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.system.Os;
import android.test.mock.MockContext;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.IpSecService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/** Unit tests for {@link IpSecManager}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class IpSecManagerTest {
private static final int TEST_UDP_ENCAP_PORT = 34567;
private static final int DROID_SPI = 0xD1201D;
private static final int DUMMY_RESOURCE_ID = 0x1234;
private static final InetAddress GOOGLE_DNS_4;
private static final String VTI_INTF_NAME = "ipsec_test";
private static final InetAddress VTI_LOCAL_ADDRESS;
private static final LinkAddress VTI_INNER_ADDRESS = new LinkAddress("10.0.1.1/24");
static {
try {
// Google Public DNS Addresses;
GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8");
VTI_LOCAL_ADDRESS = InetAddress.getByName("8.8.4.4");
} catch (UnknownHostException e) {
throw new RuntimeException("Could not resolve DNS Addresses", e);
}
}
private IpSecService mMockIpSecService;
private IpSecManager mIpSecManager;
private MockContext mMockContext = new MockContext() {
@Override
public String getOpPackageName() {
return "fooPackage";
}
};
@Before
public void setUp() throws Exception {
mMockIpSecService = mock(IpSecService.class);
mIpSecManager = new IpSecManager(mMockContext, mMockIpSecService);
}
/*
* Allocate a specific SPI
* Close SPIs
*/
@Test
public void testAllocSpi() throws Exception {
IpSecSpiResponse spiResp =
new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
when(mMockIpSecService.allocateSecurityParameterIndex(
eq(GOOGLE_DNS_4.getHostAddress()),
eq(DROID_SPI),
anyObject()))
.thenReturn(spiResp);
IpSecManager.SecurityParameterIndex droidSpi =
mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, DROID_SPI);
assertEquals(DROID_SPI, droidSpi.getSpi());
droidSpi.close();
verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
}
@Test
public void testAllocRandomSpi() throws Exception {
IpSecSpiResponse spiResp =
new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
when(mMockIpSecService.allocateSecurityParameterIndex(
eq(GOOGLE_DNS_4.getHostAddress()),
eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX),
anyObject()))
.thenReturn(spiResp);
IpSecManager.SecurityParameterIndex randomSpi =
mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
assertEquals(DROID_SPI, randomSpi.getSpi());
randomSpi.close();
verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
}
/*
* Throws resource unavailable exception
*/
@Test
public void testAllocSpiResUnavailableException() throws Exception {
IpSecSpiResponse spiResp =
new IpSecSpiResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE, 0, 0);
when(mMockIpSecService.allocateSecurityParameterIndex(
anyString(), anyInt(), anyObject()))
.thenReturn(spiResp);
try {
mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
fail("ResourceUnavailableException was not thrown");
} catch (IpSecManager.ResourceUnavailableException e) {
}
}
/*
* Throws spi unavailable exception
*/
@Test
public void testAllocSpiSpiUnavailableException() throws Exception {
IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.SPI_UNAVAILABLE, 0, 0);
when(mMockIpSecService.allocateSecurityParameterIndex(
anyString(), anyInt(), anyObject()))
.thenReturn(spiResp);
try {
mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
fail("ResourceUnavailableException was not thrown");
} catch (IpSecManager.ResourceUnavailableException e) {
}
}
/*
* Should throw exception when request spi 0 in IpSecManager
*/
@Test
public void testRequestAllocInvalidSpi() throws Exception {
try {
mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, 0);
fail("Able to allocate invalid spi");
} catch (IllegalArgumentException e) {
}
}
@Test
public void testOpenEncapsulationSocket() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
new IpSecUdpEncapResponse(
IpSecManager.Status.OK,
DUMMY_RESOURCE_ID,
TEST_UDP_ENCAP_PORT,
Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
when(mMockIpSecService.openUdpEncapsulationSocket(eq(TEST_UDP_ENCAP_PORT), anyObject()))
.thenReturn(udpEncapResp);
IpSecManager.UdpEncapsulationSocket encapSocket =
mIpSecManager.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT);
assertNotNull(encapSocket.getFileDescriptor());
assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
encapSocket.close();
verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
}
@Test
public void testApplyTransportModeTransformEnsuresSocketCreation() throws Exception {
Socket socket = new Socket();
IpSecConfig dummyConfig = new IpSecConfig();
IpSecTransform dummyTransform = new IpSecTransform(null, dummyConfig);
// Even if underlying SocketImpl is not initalized, this should force the init, and
// thereby succeed.
mIpSecManager.applyTransportModeTransform(
socket, IpSecManager.DIRECTION_IN, dummyTransform);
// Check to make sure the FileDescriptor is non-null
assertNotNull(socket.getFileDescriptor$());
}
@Test
public void testRemoveTransportModeTransformsForcesSocketCreation() throws Exception {
Socket socket = new Socket();
// Even if underlying SocketImpl is not initalized, this should force the init, and
// thereby succeed.
mIpSecManager.removeTransportModeTransforms(socket);
// Check to make sure the FileDescriptor is non-null
assertNotNull(socket.getFileDescriptor$());
}
@Test
public void testOpenEncapsulationSocketOnRandomPort() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
new IpSecUdpEncapResponse(
IpSecManager.Status.OK,
DUMMY_RESOURCE_ID,
TEST_UDP_ENCAP_PORT,
Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
when(mMockIpSecService.openUdpEncapsulationSocket(eq(0), anyObject()))
.thenReturn(udpEncapResp);
IpSecManager.UdpEncapsulationSocket encapSocket =
mIpSecManager.openUdpEncapsulationSocket();
assertNotNull(encapSocket.getFileDescriptor());
assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
encapSocket.close();
verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
}
@Test
public void testOpenEncapsulationSocketWithInvalidPort() throws Exception {
try {
mIpSecManager.openUdpEncapsulationSocket(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
fail("IllegalArgumentException was not thrown");
} catch (IllegalArgumentException e) {
}
}
// TODO: add test when applicable transform builder interface is available
private IpSecManager.IpSecTunnelInterface createAndValidateVti(int resourceId, String intfName)
throws Exception {
IpSecTunnelInterfaceResponse dummyResponse =
new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
when(mMockIpSecService.createTunnelInterface(
eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
anyObject(), anyObject(), anyString()))
.thenReturn(dummyResponse);
IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
VTI_LOCAL_ADDRESS, GOOGLE_DNS_4, mock(Network.class));
assertNotNull(tunnelIntf);
return tunnelIntf;
}
@Test
public void testCreateVti() throws Exception {
IpSecManager.IpSecTunnelInterface tunnelIntf =
createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());
tunnelIntf.close();
verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID), anyString());
}
@Test
public void testAddRemoveAddressesFromVti() throws Exception {
IpSecManager.IpSecTunnelInterface tunnelIntf =
createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
tunnelIntf.addAddress(VTI_INNER_ADDRESS.getAddress(),
VTI_INNER_ADDRESS.getPrefixLength());
verify(mMockIpSecService)
.addAddressToTunnelInterface(
eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
tunnelIntf.removeAddress(VTI_INNER_ADDRESS.getAddress(),
VTI_INNER_ADDRESS.getPrefixLength());
verify(mMockIpSecService)
.addAddressToTunnelInterface(
eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2017 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 android.net;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link IpSecTransform}. */
@SmallTest
@RunWith(JUnit4.class)
public class IpSecTransformTest {
@Test
public void testCreateTransformCopiesConfig() {
// Create a config with a few parameters to make sure it's not empty
IpSecConfig config = new IpSecConfig();
config.setSourceAddress("0.0.0.0");
config.setDestinationAddress("1.2.3.4");
config.setSpiResourceId(1984);
IpSecTransform preModification = new IpSecTransform(null, config);
config.setSpiResourceId(1985);
IpSecTransform postModification = new IpSecTransform(null, config);
assertNotEquals(preModification, postModification);
}
@Test
public void testCreateTransformsWithSameConfigEqual() {
// Create a config with a few parameters to make sure it's not empty
IpSecConfig config = new IpSecConfig();
config.setSourceAddress("0.0.0.0");
config.setDestinationAddress("1.2.3.4");
config.setSpiResourceId(1984);
IpSecTransform config1 = new IpSecTransform(null, config);
IpSecTransform config2 = new IpSecTransform(null, config);
assertEquals(config1, config2);
}
}

View File

@@ -0,0 +1,205 @@
/*
* Copyright (C) 2020 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 android.net;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.net.util.KeepalivePacketDataUtil;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.net.InetAddress;
import java.nio.ByteBuffer;
@RunWith(JUnit4.class)
public final class KeepalivePacketDataUtilTest {
private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
@Before
public void setUp() {}
@Test
public void testFromTcpKeepaliveStableParcelable() throws Exception {
final int srcPort = 1234;
final int dstPort = 4321;
final int seq = 0x11111111;
final int ack = 0x22222222;
final int wnd = 8000;
final int wndScale = 2;
final int tos = 4;
final int ttl = 64;
TcpKeepalivePacketData resultData = null;
final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
testInfo.srcPort = srcPort;
testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
testInfo.dstPort = dstPort;
testInfo.seq = seq;
testInfo.ack = ack;
testInfo.rcvWnd = wnd;
testInfo.rcvWndScale = wndScale;
testInfo.tos = tos;
testInfo.ttl = ttl;
try {
resultData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
} catch (InvalidPacketException e) {
fail("InvalidPacketException: " + e);
}
assertEquals(InetAddress.getByAddress(testInfo.srcAddress), resultData.getSrcAddress());
assertEquals(InetAddress.getByAddress(testInfo.dstAddress), resultData.getDstAddress());
assertEquals(testInfo.srcPort, resultData.getSrcPort());
assertEquals(testInfo.dstPort, resultData.getDstPort());
assertEquals(testInfo.seq, resultData.tcpSeq);
assertEquals(testInfo.ack, resultData.tcpAck);
assertEquals(testInfo.rcvWnd, resultData.tcpWindow);
assertEquals(testInfo.rcvWndScale, resultData.tcpWindowScale);
assertEquals(testInfo.tos, resultData.ipTos);
assertEquals(testInfo.ttl, resultData.ipTtl);
assertParcelingIsLossless(resultData);
final byte[] packet = resultData.getPacket();
// IP version and IHL
assertEquals(packet[0], 0x45);
// TOS
assertEquals(packet[1], tos);
// TTL
assertEquals(packet[8], ttl);
// Source IP address.
byte[] ip = new byte[4];
ByteBuffer buf = ByteBuffer.wrap(packet, 12, 4);
buf.get(ip);
assertArrayEquals(ip, IPV4_KEEPALIVE_SRC_ADDR);
// Destination IP address.
buf = ByteBuffer.wrap(packet, 16, 4);
buf.get(ip);
assertArrayEquals(ip, IPV4_KEEPALIVE_DST_ADDR);
buf = ByteBuffer.wrap(packet, 20, 12);
// Source port.
assertEquals(buf.getShort(), srcPort);
// Destination port.
assertEquals(buf.getShort(), dstPort);
// Sequence number.
assertEquals(buf.getInt(), seq);
// Ack.
assertEquals(buf.getInt(), ack);
// Window size.
buf = ByteBuffer.wrap(packet, 34, 2);
assertEquals(buf.getShort(), wnd >> wndScale);
}
//TODO: add ipv6 test when ipv6 supported
@Test
public void testToTcpKeepaliveStableParcelable() throws Exception {
final int srcPort = 1234;
final int dstPort = 4321;
final int sequence = 0x11111111;
final int ack = 0x22222222;
final int wnd = 48_000;
final int wndScale = 2;
final int tos = 4;
final int ttl = 64;
final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
testInfo.srcPort = srcPort;
testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
testInfo.dstPort = dstPort;
testInfo.seq = sequence;
testInfo.ack = ack;
testInfo.rcvWnd = wnd;
testInfo.rcvWndScale = wndScale;
testInfo.tos = tos;
testInfo.ttl = ttl;
TcpKeepalivePacketData testData = null;
TcpKeepalivePacketDataParcelable resultData = null;
testData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
resultData = KeepalivePacketDataUtil.toStableParcelable(testData);
assertArrayEquals(resultData.srcAddress, IPV4_KEEPALIVE_SRC_ADDR);
assertArrayEquals(resultData.dstAddress, IPV4_KEEPALIVE_DST_ADDR);
assertEquals(resultData.srcPort, srcPort);
assertEquals(resultData.dstPort, dstPort);
assertEquals(resultData.seq, sequence);
assertEquals(resultData.ack, ack);
assertEquals(resultData.rcvWnd, wnd);
assertEquals(resultData.rcvWndScale, wndScale);
assertEquals(resultData.tos, tos);
assertEquals(resultData.ttl, ttl);
final String expected = ""
+ "android.net.TcpKeepalivePacketDataParcelable{srcAddress: [10, 0, 0, 1],"
+ " srcPort: 1234, dstAddress: [10, 0, 0, 5], dstPort: 4321, seq: 286331153,"
+ " ack: 572662306, rcvWnd: 48000, rcvWndScale: 2, tos: 4, ttl: 64}";
assertEquals(expected, resultData.toString());
}
@Test
public void testParseTcpKeepalivePacketData() throws Exception {
final int srcPort = 1234;
final int dstPort = 4321;
final int sequence = 0x11111111;
final int ack = 0x22222222;
final int wnd = 4800;
final int wndScale = 2;
final int tos = 4;
final int ttl = 64;
final TcpKeepalivePacketDataParcelable testParcel = new TcpKeepalivePacketDataParcelable();
testParcel.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
testParcel.srcPort = srcPort;
testParcel.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
testParcel.dstPort = dstPort;
testParcel.seq = sequence;
testParcel.ack = ack;
testParcel.rcvWnd = wnd;
testParcel.rcvWndScale = wndScale;
testParcel.tos = tos;
testParcel.ttl = ttl;
final KeepalivePacketData testData =
KeepalivePacketDataUtil.fromStableParcelable(testParcel);
final TcpKeepalivePacketDataParcelable parsedParcelable =
KeepalivePacketDataUtil.parseTcpKeepalivePacketData(testData);
final TcpKeepalivePacketData roundTripData =
KeepalivePacketDataUtil.fromStableParcelable(parsedParcelable);
// Generated packet is the same, but rcvWnd / wndScale will differ if scale is non-zero
assertTrue(testData.getPacket().length > 0);
assertArrayEquals(testData.getPacket(), roundTripData.getPacket());
testParcel.rcvWndScale = 0;
final KeepalivePacketData noScaleTestData =
KeepalivePacketDataUtil.fromStableParcelable(testParcel);
final TcpKeepalivePacketDataParcelable noScaleParsedParcelable =
KeepalivePacketDataUtil.parseTcpKeepalivePacketData(noScaleTestData);
final TcpKeepalivePacketData noScaleRoundTripData =
KeepalivePacketDataUtil.fromStableParcelable(noScaleParsedParcelable);
assertEquals(noScaleTestData, noScaleRoundTripData);
assertTrue(noScaleTestData.getPacket().length > 0);
assertArrayEquals(noScaleTestData.getPacket(), noScaleRoundTripData.getPacket());
}
}

View File

@@ -0,0 +1,312 @@
/*
* Copyright 2017 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 android.net;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.net.module.util.MacAddressUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.Inet6Address;
import java.util.Arrays;
import java.util.Random;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class MacAddressTest {
static class AddrTypeTestCase {
byte[] addr;
int expectedType;
static AddrTypeTestCase of(int expectedType, int... addr) {
AddrTypeTestCase t = new AddrTypeTestCase();
t.expectedType = expectedType;
t.addr = toByteArray(addr);
return t;
}
}
@Test
public void testMacAddrTypes() {
AddrTypeTestCase[] testcases = {
AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN),
AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 0),
AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5),
AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5, 6, 7),
AddrTypeTestCase.of(MacAddress.TYPE_UNICAST, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0),
AddrTypeTestCase.of(MacAddress.TYPE_BROADCAST, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 1, 2, 3, 4, 5, 6),
AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 11, 22, 33, 44, 55, 66),
AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 33, 33, 0xaa, 0xbb, 0xcc, 0xdd)
};
for (AddrTypeTestCase t : testcases) {
int got = MacAddress.macAddressType(t.addr);
String msg = String.format("expected type of %s to be %s, but got %s",
Arrays.toString(t.addr), t.expectedType, got);
assertEquals(msg, t.expectedType, got);
if (got != MacAddress.TYPE_UNKNOWN) {
assertEquals(got, MacAddress.fromBytes(t.addr).getAddressType());
}
}
}
@Test
public void testToOuiString() {
String[][] macs = {
{"07:00:d3:56:8a:c4", "07:00:d3"},
{"33:33:aa:bb:cc:dd", "33:33:aa"},
{"06:00:00:00:00:00", "06:00:00"},
{"07:00:d3:56:8a:c4", "07:00:d3"}
};
for (String[] pair : macs) {
String mac = pair[0];
String expected = pair[1];
assertEquals(expected, MacAddress.fromString(mac).toOuiString());
}
}
@Test
public void testHexPaddingWhenPrinting() {
String[] macs = {
"07:00:d3:56:8a:c4",
"33:33:aa:bb:cc:dd",
"06:00:00:00:00:00",
"07:00:d3:56:8a:c4"
};
for (String mac : macs) {
assertEquals(mac, MacAddress.fromString(mac).toString());
assertEquals(mac,
MacAddress.stringAddrFromByteAddr(MacAddress.byteAddrFromStringAddr(mac)));
}
}
@Test
public void testIsMulticastAddress() {
MacAddress[] multicastAddresses = {
MacAddress.BROADCAST_ADDRESS,
MacAddress.fromString("07:00:d3:56:8a:c4"),
MacAddress.fromString("33:33:aa:bb:cc:dd"),
};
MacAddress[] unicastAddresses = {
MacAddress.ALL_ZEROS_ADDRESS,
MacAddress.fromString("00:01:44:55:66:77"),
MacAddress.fromString("08:00:22:33:44:55"),
MacAddress.fromString("06:00:00:00:00:00"),
};
for (MacAddress mac : multicastAddresses) {
String msg = mac.toString() + " expected to be a multicast address";
assertTrue(msg, MacAddressUtils.isMulticastAddress(mac));
}
for (MacAddress mac : unicastAddresses) {
String msg = mac.toString() + " expected not to be a multicast address";
assertFalse(msg, MacAddressUtils.isMulticastAddress(mac));
}
}
@Test
public void testIsLocallyAssignedAddress() {
MacAddress[] localAddresses = {
MacAddress.fromString("06:00:00:00:00:00"),
MacAddress.fromString("07:00:d3:56:8a:c4"),
MacAddress.fromString("33:33:aa:bb:cc:dd"),
};
MacAddress[] universalAddresses = {
MacAddress.fromString("00:01:44:55:66:77"),
MacAddress.fromString("08:00:22:33:44:55"),
};
for (MacAddress mac : localAddresses) {
String msg = mac.toString() + " expected to be a locally assigned address";
assertTrue(msg, mac.isLocallyAssigned());
}
for (MacAddress mac : universalAddresses) {
String msg = mac.toString() + " expected not to be globally unique address";
assertFalse(msg, mac.isLocallyAssigned());
}
}
@Test
public void testMacAddressConversions() {
final int iterations = 10000;
for (int i = 0; i < iterations; i++) {
MacAddress mac = MacAddressUtils.createRandomUnicastAddress();
String stringRepr = mac.toString();
byte[] bytesRepr = mac.toByteArray();
assertEquals(mac, MacAddress.fromString(stringRepr));
assertEquals(mac, MacAddress.fromBytes(bytesRepr));
assertEquals(mac, MacAddress.fromString(MacAddress.stringAddrFromByteAddr(bytesRepr)));
assertEquals(mac, MacAddress.fromBytes(MacAddress.byteAddrFromStringAddr(stringRepr)));
}
}
@Test
public void testMacAddressRandomGeneration() {
final int iterations = 1000;
final String expectedAndroidOui = "da:a1:19";
for (int i = 0; i < iterations; i++) {
MacAddress mac = MacAddress.createRandomUnicastAddressWithGoogleBase();
String stringRepr = mac.toString();
assertTrue(stringRepr + " expected to be a locally assigned address",
mac.isLocallyAssigned());
assertTrue(stringRepr + " expected to begin with " + expectedAndroidOui,
stringRepr.startsWith(expectedAndroidOui));
}
final Random r = new Random();
final String anotherOui = "24:5f:78";
final String expectedLocalOui = "26:5f:78";
final MacAddress base = MacAddress.fromString(anotherOui + ":0:0:0");
for (int i = 0; i < iterations; i++) {
MacAddress mac = MacAddressUtils.createRandomUnicastAddress(base, r);
String stringRepr = mac.toString();
assertTrue(stringRepr + " expected to be a locally assigned address",
mac.isLocallyAssigned());
assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType());
assertTrue(stringRepr + " expected to begin with " + expectedLocalOui,
stringRepr.startsWith(expectedLocalOui));
}
for (int i = 0; i < iterations; i++) {
MacAddress mac = MacAddressUtils.createRandomUnicastAddress();
String stringRepr = mac.toString();
assertTrue(stringRepr + " expected to be a locally assigned address",
mac.isLocallyAssigned());
assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType());
}
}
@Test
public void testConstructorInputValidation() {
String[] invalidStringAddresses = {
"",
"abcd",
"1:2:3:4:5",
"1:2:3:4:5:6:7",
"10000:2:3:4:5:6",
};
for (String s : invalidStringAddresses) {
try {
MacAddress mac = MacAddress.fromString(s);
fail("MacAddress.fromString(" + s + ") should have failed, but returned " + mac);
} catch (IllegalArgumentException excepted) {
}
}
try {
MacAddress mac = MacAddress.fromString(null);
fail("MacAddress.fromString(null) should have failed, but returned " + mac);
} catch (NullPointerException excepted) {
}
byte[][] invalidBytesAddresses = {
{},
{1,2,3,4,5},
{1,2,3,4,5,6,7},
};
for (byte[] b : invalidBytesAddresses) {
try {
MacAddress mac = MacAddress.fromBytes(b);
fail("MacAddress.fromBytes(" + Arrays.toString(b)
+ ") should have failed, but returned " + mac);
} catch (IllegalArgumentException excepted) {
}
}
try {
MacAddress mac = MacAddress.fromBytes(null);
fail("MacAddress.fromBytes(null) should have failed, but returned " + mac);
} catch (NullPointerException excepted) {
}
}
@Test
public void testMatches() {
// match 4 bytes prefix
assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
MacAddress.fromString("aa:bb:cc:dd:00:00"),
MacAddress.fromString("ff:ff:ff:ff:00:00")));
// match bytes 0,1,2 and 5
assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
MacAddress.fromString("aa:bb:cc:00:00:11"),
MacAddress.fromString("ff:ff:ff:00:00:ff")));
// match 34 bit prefix
assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
MacAddress.fromString("aa:bb:cc:dd:c0:00"),
MacAddress.fromString("ff:ff:ff:ff:c0:00")));
// fail to match 36 bit prefix
assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
MacAddress.fromString("aa:bb:cc:dd:40:00"),
MacAddress.fromString("ff:ff:ff:ff:f0:00")));
// match all 6 bytes
assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
MacAddress.fromString("aa:bb:cc:dd:ee:11"),
MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
// match none of 6 bytes
assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
MacAddress.fromString("00:00:00:00:00:00"),
MacAddress.fromString("00:00:00:00:00:00")));
}
/**
* Tests that link-local address generation from MAC is valid.
*/
@Test
public void testLinkLocalFromMacGeneration() {
MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x74,
(byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f};
Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac();
assertTrue(llv6.isLinkLocalAddress());
assertArrayEquals(inet6ll, llv6.getAddress());
}
static byte[] toByteArray(int... in) {
byte[] out = new byte[in.length];
for (int i = 0; i < in.length; i++) {
out[i] = (byte) in[i];
}
return out;
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2021 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 android.net
import android.net.NetworkIdentity.OEM_NONE
import android.net.NetworkIdentity.OEM_PAID
import android.net.NetworkIdentity.OEM_PRIVATE
import android.net.NetworkIdentity.getOemBitfield
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import kotlin.test.assertEquals
@RunWith(JUnit4::class)
class NetworkIdentityTest {
@Test
fun testGetOemBitfield() {
val oemNone = NetworkCapabilities().apply {
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
}
val oemPaid = NetworkCapabilities().apply {
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
}
val oemPrivate = NetworkCapabilities().apply {
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
}
val oemAll = NetworkCapabilities().apply {
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
}
assertEquals(getOemBitfield(oemNone), OEM_NONE)
assertEquals(getOemBitfield(oemPaid), OEM_PAID)
assertEquals(getOemBitfield(oemPrivate), OEM_PRIVATE)
assertEquals(getOemBitfield(oemAll), OEM_PAID or OEM_PRIVATE)
}
}

View File

@@ -0,0 +1,599 @@
/*
* Copyright (C) 2011 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 android.net;
import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkStatsHistory.FIELD_OPERATIONS;
import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
import static android.net.NetworkStatsHistory.FIELD_RX_PACKETS;
import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
import static android.net.TrafficStats.GB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.tests.net.R;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.Random;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkStatsHistoryTest {
private static final String TAG = "NetworkStatsHistoryTest";
private static final long TEST_START = 1194220800000L;
private NetworkStatsHistory stats;
@After
public void tearDown() throws Exception {
if (stats != null) {
assertConsistent(stats);
}
}
@Test
public void testReadOriginalVersion() throws Exception {
final Context context = InstrumentationRegistry.getContext();
final DataInputStream in =
new DataInputStream(context.getResources().openRawResource(R.raw.history_v1));
NetworkStatsHistory.Entry entry = null;
try {
final NetworkStatsHistory history = new NetworkStatsHistory(in);
assertEquals(15 * SECOND_IN_MILLIS, history.getBucketDuration());
entry = history.getValues(0, entry);
assertEquals(29143L, entry.rxBytes);
assertEquals(6223L, entry.txBytes);
entry = history.getValues(history.size() - 1, entry);
assertEquals(1476L, entry.rxBytes);
assertEquals(838L, entry.txBytes);
entry = history.getValues(Long.MIN_VALUE, Long.MAX_VALUE, entry);
assertEquals(332401L, entry.rxBytes);
assertEquals(64314L, entry.txBytes);
} finally {
in.close();
}
}
@Test
public void testRecordSingleBucket() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
// record data into narrow window to get single bucket
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
assertEquals(1, stats.size());
assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L);
}
@Test
public void testRecordEqualBuckets() throws Exception {
final long bucketDuration = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(bucketDuration);
// split equally across two buckets
final long recordStart = TEST_START + (bucketDuration / 2);
stats.recordData(recordStart, recordStart + bucketDuration,
new NetworkStats.Entry(1024L, 10L, 128L, 2L, 2L));
assertEquals(2, stats.size());
assertValues(stats, 0, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
assertValues(stats, 1, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
}
@Test
public void testRecordTouchingBuckets() throws Exception {
final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
// split almost completely into middle bucket, but with a few minutes
// overlap into neighboring buckets. total record is 20 minutes.
final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
stats.recordData(recordStart, recordEnd,
new NetworkStats.Entry(1000L, 2000L, 5000L, 10000L, 100L));
assertEquals(3, stats.size());
// first bucket should have (1/20 of value)
assertValues(stats, 0, MINUTE_IN_MILLIS, 50L, 100L, 250L, 500L, 5L);
// second bucket should have (15/20 of value)
assertValues(stats, 1, 15 * MINUTE_IN_MILLIS, 750L, 1500L, 3750L, 7500L, 75L);
// final bucket should have (4/20 of value)
assertValues(stats, 2, 4 * MINUTE_IN_MILLIS, 200L, 400L, 1000L, 2000L, 20L);
}
@Test
public void testRecordGapBuckets() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
// record some data today and next week with large gap
final long firstStart = TEST_START;
final long lastStart = TEST_START + WEEK_IN_MILLIS;
stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS,
new NetworkStats.Entry(128L, 2L, 256L, 4L, 1L));
stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS,
new NetworkStats.Entry(64L, 1L, 512L, 8L, 2L));
// we should have two buckets, far apart from each other
assertEquals(2, stats.size());
assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
assertValues(stats, 1, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
// now record something in middle, spread across two buckets
final long middleStart = TEST_START + DAY_IN_MILLIS;
final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
stats.recordData(middleStart, middleEnd,
new NetworkStats.Entry(2048L, 4L, 2048L, 4L, 2L));
// now should have four buckets, with new record in middle two buckets
assertEquals(4, stats.size());
assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
assertValues(stats, 1, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
assertValues(stats, 2, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
assertValues(stats, 3, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
}
@Test
public void testRecordOverlapBuckets() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
// record some data in one bucket, and another overlapping buckets
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
new NetworkStats.Entry(256L, 2L, 256L, 2L, 1L));
final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
stats.recordData(midStart, midStart + HOUR_IN_MILLIS,
new NetworkStats.Entry(1024L, 10L, 1024L, 10L, 10L));
// should have two buckets, with some data mixed together
assertEquals(2, stats.size());
assertValues(stats, 0, SECOND_IN_MILLIS + (HOUR_IN_MILLIS / 2), 768L, 7L, 768L, 7L, 6L);
assertValues(stats, 1, (HOUR_IN_MILLIS / 2), 512L, 5L, 512L, 5L, 5L);
}
@Test
public void testRecordEntireGapIdentical() throws Exception {
// first, create two separate histories far apart
final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L);
final long TEST_START_2 = TEST_START + DAY_IN_MILLIS;
final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L);
// combine together with identical bucket size
stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats.recordEntireHistory(stats1);
stats.recordEntireHistory(stats2);
// first verify that totals match up
assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L);
// now inspect internal buckets
assertValues(stats, 0, 1000L, 500L);
assertValues(stats, 1, 1000L, 500L);
assertValues(stats, 2, 500L, 250L);
assertValues(stats, 3, 500L, 250L);
}
@Test
public void testRecordEntireOverlapVaryingBuckets() throws Exception {
// create history just over hour bucket boundary
final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L);
final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS;
final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS);
stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L);
// combine together with minute bucket size
stats = new NetworkStatsHistory(MINUTE_IN_MILLIS);
stats.recordEntireHistory(stats1);
stats.recordEntireHistory(stats2);
// first verify that totals match up
assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
// now inspect internal buckets
assertValues(stats, 0, 10L, 10L);
assertValues(stats, 1, 20L, 20L);
assertValues(stats, 2, 20L, 20L);
assertValues(stats, 3, 20L, 20L);
assertValues(stats, 4, 20L, 20L);
assertValues(stats, 5, 20L, 20L);
assertValues(stats, 6, 10L, 10L);
// now combine using 15min buckets
stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4);
stats.recordEntireHistory(stats1);
stats.recordEntireHistory(stats2);
// first verify that totals match up
assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
// and inspect buckets
assertValues(stats, 0, 200L, 200L);
assertValues(stats, 1, 150L, 150L);
assertValues(stats, 2, 150L, 150L);
assertValues(stats, 3, 150L, 150L);
}
@Test
public void testRemove() throws Exception {
stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
// record some data across 24 buckets
stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
assertEquals(24, stats.size());
// try removing invalid data; should be no change
stats.removeBucketsBefore(0 - DAY_IN_MILLIS);
assertEquals(24, stats.size());
// try removing far before buckets; should be no change
stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS);
assertEquals(24, stats.size());
// try removing just moments into first bucket; should be no change
// since that bucket contains data beyond the cutoff
stats.removeBucketsBefore(TEST_START + SECOND_IN_MILLIS);
assertEquals(24, stats.size());
// try removing single bucket
stats.removeBucketsBefore(TEST_START + HOUR_IN_MILLIS);
assertEquals(23, stats.size());
// try removing multiple buckets
stats.removeBucketsBefore(TEST_START + (4 * HOUR_IN_MILLIS));
assertEquals(20, stats.size());
// try removing all buckets
stats.removeBucketsBefore(TEST_START + YEAR_IN_MILLIS);
assertEquals(0, stats.size());
}
@Test
public void testTotalData() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
// record uniform data across day
stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L);
// verify that total outside range is 0
assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L);
// verify total in first hour
assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L);
// verify total across 1.5 hours
assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L);
// verify total beyond end
assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L);
// verify everything total
assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L);
}
@Test
public void testFuzzing() throws Exception {
try {
// fuzzing with random events, looking for crashes
final NetworkStats.Entry entry = new NetworkStats.Entry();
final Random r = new Random();
for (int i = 0; i < 500; i++) {
stats = new NetworkStatsHistory(r.nextLong());
for (int j = 0; j < 10000; j++) {
if (r.nextBoolean()) {
// add range
final long start = r.nextLong();
final long end = start + r.nextInt();
entry.rxBytes = nextPositiveLong(r);
entry.rxPackets = nextPositiveLong(r);
entry.txBytes = nextPositiveLong(r);
entry.txPackets = nextPositiveLong(r);
entry.operations = nextPositiveLong(r);
stats.recordData(start, end, entry);
} else {
// trim something
stats.removeBucketsBefore(r.nextLong());
}
}
assertConsistent(stats);
}
} catch (Throwable e) {
Log.e(TAG, String.valueOf(stats));
throw new RuntimeException(e);
}
}
private static long nextPositiveLong(Random r) {
final long value = r.nextLong();
return value < 0 ? -value : value;
}
@Test
public void testIgnoreFields() throws Exception {
final NetworkStatsHistory history = new NetworkStatsHistory(
MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
history.recordData(0, MINUTE_IN_MILLIS,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
history.recordData(0, 2 * MINUTE_IN_MILLIS,
new NetworkStats.Entry(2L, 2L, 2L, 2L, 2L));
assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
}
@Test
public void testIgnoreFieldsRecordIn() throws Exception {
final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
final NetworkStatsHistory partial = new NetworkStatsHistory(
MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
full.recordData(0, MINUTE_IN_MILLIS,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
partial.recordEntireHistory(full);
assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
}
@Test
public void testIgnoreFieldsRecordOut() throws Exception {
final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
final NetworkStatsHistory partial = new NetworkStatsHistory(
MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
partial.recordData(0, MINUTE_IN_MILLIS,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
full.recordEntireHistory(partial);
assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L);
}
@Test
public void testSerialize() throws Exception {
final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
before.recordData(0, 4 * MINUTE_IN_MILLIS,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS,
new NetworkStats.Entry(10L, 20L, 30L, 40L, 50L));
final ByteArrayOutputStream out = new ByteArrayOutputStream();
before.writeToStream(new DataOutputStream(out));
out.close();
final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in));
// must have identical totals before and after
assertFullValues(before, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
assertFullValues(after, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
}
@Test
public void testVarLong() throws Exception {
assertEquals(0L, performVarLong(0L));
assertEquals(-1L, performVarLong(-1L));
assertEquals(1024L, performVarLong(1024L));
assertEquals(-1024L, performVarLong(-1024L));
assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES));
assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES));
assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE));
assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE));
assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40));
assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
}
@Test
public void testIndexBeforeAfter() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
final long FIRST_START = TEST_START;
final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
stats.recordData(FIRST_START, FIRST_END,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
stats.recordData(SECOND_START, SECOND_END,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
stats.recordData(THIRD_START, THIRD_END,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
// should have buckets: 2+1+2
assertEquals(5, stats.size());
assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE);
assertIndexBeforeAfter(stats, 0, 1, FIRST_START);
assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS);
assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS);
assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS);
assertIndexBeforeAfter(stats, 1, 2, FIRST_END);
assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS);
assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS);
assertIndexBeforeAfter(stats, 1, 3, SECOND_START);
assertIndexBeforeAfter(stats, 2, 3, SECOND_END);
assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS);
assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS);
assertIndexBeforeAfter(stats, 2, 4, THIRD_START);
assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS);
assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS);
assertIndexBeforeAfter(stats, 4, 4, THIRD_END);
assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS);
assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
}
@Test
public void testIntersects() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
final long FIRST_START = TEST_START;
final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
stats.recordData(FIRST_START, FIRST_END,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
stats.recordData(SECOND_START, SECOND_END,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
stats.recordData(THIRD_START, THIRD_END,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
assertFalse(stats.intersects(10, 20));
assertFalse(stats.intersects(TEST_START + YEAR_IN_MILLIS, TEST_START + YEAR_IN_MILLIS + 1));
assertFalse(stats.intersects(Long.MAX_VALUE, Long.MIN_VALUE));
assertTrue(stats.intersects(Long.MIN_VALUE, Long.MAX_VALUE));
assertTrue(stats.intersects(10, TEST_START + YEAR_IN_MILLIS));
assertTrue(stats.intersects(TEST_START, TEST_START));
assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, TEST_START + DAY_IN_MILLIS + 1));
assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, Long.MAX_VALUE));
assertTrue(stats.intersects(TEST_START + 1, Long.MAX_VALUE));
assertFalse(stats.intersects(Long.MIN_VALUE, TEST_START - 1));
assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START));
assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1));
}
@Test
public void testSetValues() throws Exception {
stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats.recordData(TEST_START, TEST_START + 1,
new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
assertEquals(1024L + 2048L, stats.getTotalBytes());
final NetworkStatsHistory.Entry entry = stats.getValues(0, null);
entry.rxBytes /= 2;
entry.txBytes *= 2;
stats.setValues(0, entry);
assertEquals(512L + 4096L, stats.getTotalBytes());
}
private static void assertIndexBeforeAfter(
NetworkStatsHistory stats, int before, int after, long time) {
assertEquals("unexpected before", before, stats.getIndexBefore(time));
assertEquals("unexpected after", after, stats.getIndexAfter(time));
}
private static long performVarLong(long before) throws Exception {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
writeVarLong(new DataOutputStream(out), before);
final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
return readVarLong(new DataInputStream(in));
}
private static void assertConsistent(NetworkStatsHistory stats) {
// verify timestamps are monotonic
long lastStart = Long.MIN_VALUE;
NetworkStatsHistory.Entry entry = null;
for (int i = 0; i < stats.size(); i++) {
entry = stats.getValues(i, entry);
assertTrue(lastStart < entry.bucketStart);
lastStart = entry.bucketStart;
}
}
private static void assertValues(
NetworkStatsHistory stats, int index, long rxBytes, long txBytes) {
final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
}
private static void assertValues(
NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) {
final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
}
private static void assertValues(NetworkStatsHistory stats, int index, long activeTime,
long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
assertEquals("unexpected activeTime", activeTime, entry.activeTime);
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
assertEquals("unexpected txPackets", txPackets, entry.txPackets);
assertEquals("unexpected operations", operations, entry.operations);
}
private static void assertFullValues(NetworkStatsHistory stats, long activeTime, long rxBytes,
long rxPackets, long txBytes, long txPackets, long operations) {
assertValues(stats, Long.MIN_VALUE, Long.MAX_VALUE, activeTime, rxBytes, rxPackets, txBytes,
txPackets, operations);
}
private static void assertValues(NetworkStatsHistory stats, long start, long end,
long activeTime, long rxBytes, long rxPackets, long txBytes, long txPackets,
long operations) {
final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
assertEquals("unexpected activeTime", activeTime, entry.activeTime);
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
assertEquals("unexpected txPackets", txPackets, entry.txPackets);
assertEquals("unexpected operations", operations, entry.operations);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,351 @@
/*
* Copyright (C) 2020 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 android.net
import android.content.Context
import android.net.ConnectivityManager.TYPE_MOBILE
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.NetworkIdentity.SUBTYPE_COMBINED
import android.net.NetworkIdentity.OEM_NONE
import android.net.NetworkIdentity.OEM_PAID
import android.net.NetworkIdentity.OEM_PRIVATE
import android.net.NetworkIdentity.buildNetworkIdentity
import android.net.NetworkStats.DEFAULT_NETWORK_ALL
import android.net.NetworkStats.METERED_ALL
import android.net.NetworkStats.ROAMING_ALL
import android.net.NetworkTemplate.MATCH_MOBILE
import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
import android.net.NetworkTemplate.MATCH_WIFI
import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
import android.net.NetworkTemplate.WIFI_NETWORKID_ALL
import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
import android.net.NetworkTemplate.OEM_MANAGED_ALL
import android.net.NetworkTemplate.OEM_MANAGED_NO
import android.net.NetworkTemplate.OEM_MANAGED_YES
import android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT
import android.net.NetworkTemplate.buildTemplateWifi
import android.net.NetworkTemplate.buildTemplateWifiWildcard
import android.net.NetworkTemplate.buildTemplateCarrier
import android.net.NetworkTemplate.buildTemplateMobileWithRatType
import android.telephony.TelephonyManager
import com.android.testutils.assertParcelSane
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
private const val TEST_IMSI1 = "imsi1"
private const val TEST_IMSI2 = "imsi2"
private const val TEST_SSID1 = "ssid1"
private const val TEST_SSID2 = "ssid2"
@RunWith(JUnit4::class)
class NetworkTemplateTest {
private val mockContext = mock(Context::class.java)
private fun buildMobileNetworkState(subscriberId: String): NetworkStateSnapshot =
buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId)
private fun buildWifiNetworkState(subscriberId: String?, ssid: String?): NetworkStateSnapshot =
buildNetworkState(TYPE_WIFI, subscriberId = subscriberId, ssid = ssid)
private fun buildNetworkState(
type: Int,
subscriberId: String? = null,
ssid: String? = null,
oemManaged: Int = OEM_NONE
): NetworkStateSnapshot {
val lp = LinkProperties()
val caps = NetworkCapabilities().apply {
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
setSSID(ssid)
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID,
(oemManaged and OEM_PAID) == OEM_PAID)
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
(oemManaged and OEM_PRIVATE) == OEM_PRIVATE)
}
return NetworkStateSnapshot(mock(Network::class.java), caps, lp, subscriberId, type)
}
private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
assertTrue(matches(ident), "$this does not match $ident")
private fun NetworkTemplate.assertDoesNotMatch(ident: NetworkIdentity) =
assertFalse(matches(ident), "$this should match $ident")
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
}
@Test
fun testWifiWildcardMatches() {
val templateWifiWildcard = buildTemplateWifiWildcard()
val identMobileImsi1 = buildNetworkIdentity(mockContext,
buildMobileNetworkState(TEST_IMSI1),
false, TelephonyManager.NETWORK_TYPE_UMTS)
val identWifiImsiNullSsid1 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
val identWifiImsi1Ssid1 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
templateWifiWildcard.assertDoesNotMatch(identMobileImsi1)
templateWifiWildcard.assertMatches(identWifiImsiNullSsid1)
templateWifiWildcard.assertMatches(identWifiImsi1Ssid1)
}
@Test
fun testWifiMatches() {
val templateWifiSsid1 = buildTemplateWifi(TEST_SSID1)
val templateWifiSsid1ImsiNull = buildTemplateWifi(TEST_SSID1, null)
val templateWifiSsid1Imsi1 = buildTemplateWifi(TEST_SSID1, TEST_IMSI1)
val templateWifiSsidAllImsi1 = buildTemplateWifi(WIFI_NETWORKID_ALL, TEST_IMSI1)
val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1),
false, TelephonyManager.NETWORK_TYPE_UMTS)
val identWifiImsiNullSsid1 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
val identWifiImsi1Ssid1 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
val identWifiImsi2Ssid1 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0)
val identWifiImsi1Ssid2 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID2), true, 0)
// Verify that template with SSID only matches any subscriberId and specific SSID.
templateWifiSsid1.assertDoesNotMatch(identMobile1)
templateWifiSsid1.assertMatches(identWifiImsiNullSsid1)
templateWifiSsid1.assertMatches(identWifiImsi1Ssid1)
templateWifiSsid1.assertMatches(identWifiImsi2Ssid1)
templateWifiSsid1.assertDoesNotMatch(identWifiImsi1Ssid2)
// Verify that template with SSID1 and null imsi matches any network with
// SSID1 and null imsi.
templateWifiSsid1ImsiNull.assertDoesNotMatch(identMobile1)
templateWifiSsid1ImsiNull.assertMatches(identWifiImsiNullSsid1)
templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid1)
templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi2Ssid1)
templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid2)
// Verify that template with SSID1 and imsi1 matches any network with
// SSID1 and imsi1.
templateWifiSsid1Imsi1.assertDoesNotMatch(identMobile1)
templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsiNullSsid1)
templateWifiSsid1Imsi1.assertMatches(identWifiImsi1Ssid1)
templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi2Ssid1)
templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi1Ssid2)
// Verify that template with SSID all and imsi1 matches any network with
// any SSID and imsi1.
templateWifiSsidAllImsi1.assertDoesNotMatch(identMobile1)
templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsiNullSsid1)
templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid1)
templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsi2Ssid1)
templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid2)
}
@Test
fun testCarrierMatches() {
val templateCarrierImsi1 = buildTemplateCarrier(TEST_IMSI1)
val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1),
false, TelephonyManager.NETWORK_TYPE_UMTS)
val identMobile2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2),
false, TelephonyManager.NETWORK_TYPE_UMTS)
val identWifiSsid1 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
val identCarrierWifiImsi1 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
val identCarrierWifiImsi2 = buildNetworkIdentity(
mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0)
templateCarrierImsi1.assertMatches(identCarrierWifiImsi1)
templateCarrierImsi1.assertDoesNotMatch(identCarrierWifiImsi2)
templateCarrierImsi1.assertDoesNotMatch(identWifiSsid1)
templateCarrierImsi1.assertMatches(identMobile1)
templateCarrierImsi1.assertDoesNotMatch(identMobile2)
}
@Test
fun testRatTypeGroupMatches() {
val stateMobile = buildMobileNetworkState(TEST_IMSI1)
// Build UMTS template that matches mobile identities with RAT in the same
// group with any IMSI. See {@link NetworkTemplate#getCollapsedRatType}.
val templateUmts = buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS)
// Build normal template that matches mobile identities with any RAT and IMSI.
val templateAll = buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL)
// Build template with UNKNOWN RAT that matches mobile identities with RAT that
// cannot be determined.
val templateUnknown =
buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN)
val identUmts = buildNetworkIdentity(
mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_UMTS)
val identHsdpa = buildNetworkIdentity(
mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_HSDPA)
val identLte = buildNetworkIdentity(
mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_LTE)
val identCombined = buildNetworkIdentity(
mockContext, stateMobile, false, SUBTYPE_COMBINED)
val identImsi2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2),
false, TelephonyManager.NETWORK_TYPE_UMTS)
val identWifi = buildNetworkIdentity(
mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
// Assert that identity with the same RAT matches.
templateUmts.assertMatches(identUmts)
templateAll.assertMatches(identUmts)
templateUnknown.assertDoesNotMatch(identUmts)
// Assert that identity with the RAT within the same group matches.
templateUmts.assertMatches(identHsdpa)
templateAll.assertMatches(identHsdpa)
templateUnknown.assertDoesNotMatch(identHsdpa)
// Assert that identity with the RAT out of the same group only matches template with
// NETWORK_TYPE_ALL.
templateUmts.assertDoesNotMatch(identLte)
templateAll.assertMatches(identLte)
templateUnknown.assertDoesNotMatch(identLte)
// Assert that identity with combined RAT only matches with template with NETWORK_TYPE_ALL
// and NETWORK_TYPE_UNKNOWN.
templateUmts.assertDoesNotMatch(identCombined)
templateAll.assertMatches(identCombined)
templateUnknown.assertMatches(identCombined)
// Assert that identity with different IMSI matches.
templateUmts.assertMatches(identImsi2)
templateAll.assertMatches(identImsi2)
templateUnknown.assertDoesNotMatch(identImsi2)
// Assert that wifi identity does not match.
templateUmts.assertDoesNotMatch(identWifi)
templateAll.assertDoesNotMatch(identWifi)
templateUnknown.assertDoesNotMatch(identWifi)
}
@Test
fun testParcelUnparcel() {
val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL,
ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE,
OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL,
ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL,
SUBSCRIBER_ID_MATCH_RULE_EXACT)
val templateOem = NetworkTemplate(MATCH_MOBILE, null, null, null, METERED_ALL,
ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES,
SUBSCRIBER_ID_MATCH_RULE_EXACT)
assertParcelSane(templateMobile, 10)
assertParcelSane(templateWifi, 10)
assertParcelSane(templateOem, 10)
}
// Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
// TelephonyManager#NETWORK_TYPE_* constants.
@Test
fun testNetworkTypeConstants() {
for (ratType in TelephonyManager.getAllNetworkTypes()) {
assertNotEquals(NETWORK_TYPE_ALL, ratType)
assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
}
}
@Test
fun testOemNetworkConstants() {
val constantValues = arrayOf(OEM_MANAGED_YES, OEM_MANAGED_ALL, OEM_MANAGED_NO,
OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
// Verify that "not OEM managed network" constants are equal.
assertEquals(OEM_MANAGED_NO, OEM_NONE)
// Verify the constants don't conflict.
assertEquals(constantValues.size, constantValues.distinct().count())
}
/**
* Helper to enumerate and assert OEM managed wifi and mobile {@code NetworkTemplate}s match
* their the appropriate OEM managed {@code NetworkIdentity}s.
*
* @param networkType {@code TYPE_MOBILE} or {@code TYPE_WIFI}
* @param matchType A match rule from {@code NetworkTemplate.MATCH_*} corresponding to the
* networkType.
* @param subscriberId To be populated with {@code TEST_IMSI*} only if networkType is
* {@code TYPE_MOBILE}. May be left as null when matchType is
* {@link NetworkTemplate.MATCH_MOBILE_WILDCARD}.
* @param templateSsid Top be populated with {@code TEST_SSID*} only if networkType is
* {@code TYPE_WIFI}. May be left as null when matchType is
* {@link NetworkTemplate.MATCH_WIFI_WILDCARD}.
* @param identSsid If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide
* one of {@code TEST_SSID*}.
*/
private fun matchOemManagedIdent(
networkType: Int,
matchType: Int,
subscriberId: String? = null,
templateSsid: String? = null,
identSsid: String? = null
) {
val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
val matchSubscriberIds = arrayOf(subscriberId)
val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
OEM_MANAGED_YES, SUBSCRIBER_ID_MATCH_RULE_EXACT)
val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
for (identityOemManagedState in oemManagedStates) {
val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType,
subscriberId, identSsid, identityOemManagedState), /*defaultNetwork=*/false,
/*subType=*/0)
// Create a template with each OEM managed type and match it against the NetworkIdentity
for (templateOemManagedState in oemManagedStates) {
val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
NETWORK_TYPE_ALL, templateOemManagedState, SUBSCRIBER_ID_MATCH_RULE_EXACT)
if (identityOemManagedState == templateOemManagedState) {
template.assertMatches(ident)
} else {
template.assertDoesNotMatch(ident)
}
}
// OEM_MANAGED_ALL ignores OEM state.
templateOemAll.assertMatches(ident)
if (identityOemManagedState == OEM_NONE) {
// OEM_MANAGED_YES matches everything except OEM_NONE.
templateOemYes.assertDoesNotMatch(ident)
} else {
templateOemYes.assertMatches(ident)
}
}
}
@Test
fun testOemManagedMatchesIdent() {
matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE, subscriberId = TEST_IMSI1)
matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE_WILDCARD)
matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, templateSsid = TEST_SSID1,
identSsid = TEST_SSID1)
matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI_WILDCARD, identSsid = TEST_SSID1)
}
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2015 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 android.net;
import static junit.framework.Assert.assertEquals;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.math.BigInteger;
import java.util.TreeSet;
@RunWith(AndroidJUnit4.class)
@androidx.test.filters.SmallTest
public class NetworkUtilsTest {
@Test
public void testRoutedIPv4AddressCount() {
final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
// No routes routes to no addresses.
assertEquals(0, NetworkUtils.routedIPv4AddressCount(set));
set.add(new IpPrefix("0.0.0.0/0"));
assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
set.add(new IpPrefix("20.18.0.0/16"));
set.add(new IpPrefix("20.18.0.0/24"));
set.add(new IpPrefix("20.18.0.0/8"));
// There is a default route, still covers everything
assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
set.clear();
set.add(new IpPrefix("20.18.0.0/24"));
set.add(new IpPrefix("20.18.0.0/8"));
// The 8-length includes the 24-length prefix
assertEquals(1l << 24, NetworkUtils.routedIPv4AddressCount(set));
set.add(new IpPrefix("10.10.10.126/25"));
// The 8-length does not include this 25-length prefix
assertEquals((1l << 24) + (1 << 7), NetworkUtils.routedIPv4AddressCount(set));
set.clear();
set.add(new IpPrefix("1.2.3.4/32"));
set.add(new IpPrefix("1.2.3.4/32"));
set.add(new IpPrefix("1.2.3.4/32"));
set.add(new IpPrefix("1.2.3.4/32"));
assertEquals(1l, NetworkUtils.routedIPv4AddressCount(set));
set.add(new IpPrefix("1.2.3.5/32"));
set.add(new IpPrefix("1.2.3.6/32"));
set.add(new IpPrefix("1.2.3.7/32"));
set.add(new IpPrefix("1.2.3.8/32"));
set.add(new IpPrefix("1.2.3.9/32"));
set.add(new IpPrefix("1.2.3.0/32"));
assertEquals(7l, NetworkUtils.routedIPv4AddressCount(set));
// 1.2.3.4/30 eats 1.2.3.{4-7}/32
set.add(new IpPrefix("1.2.3.4/30"));
set.add(new IpPrefix("6.2.3.4/28"));
set.add(new IpPrefix("120.2.3.4/16"));
assertEquals(7l - 4 + 4 + 16 + 65536, NetworkUtils.routedIPv4AddressCount(set));
}
@Test
public void testRoutedIPv6AddressCount() {
final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
// No routes routes to no addresses.
assertEquals(BigInteger.ZERO, NetworkUtils.routedIPv6AddressCount(set));
set.add(new IpPrefix("::/0"));
assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
set.add(new IpPrefix("1234:622a::18/64"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
// There is a default route, still covers everything
assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
set.clear();
set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
// The 8-length includes the 96-length prefix
assertEquals(BigInteger.ONE.shiftLeft(120), NetworkUtils.routedIPv6AddressCount(set));
set.add(new IpPrefix("10::26/64"));
// The 8-length does not include this 64-length prefix
assertEquals(BigInteger.ONE.shiftLeft(120).add(BigInteger.ONE.shiftLeft(64)),
NetworkUtils.routedIPv6AddressCount(set));
set.clear();
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
assertEquals(BigInteger.ONE, NetworkUtils.routedIPv6AddressCount(set));
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad5/128"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad6/128"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad7/128"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad8/128"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad9/128"));
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad0/128"));
assertEquals(BigInteger.valueOf(7), NetworkUtils.routedIPv6AddressCount(set));
// add4:f00:80:f7:1111::6ad4/126 eats add4:f00:8[:f7:1111::6ad{4-7}/128
set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/126"));
set.add(new IpPrefix("d00d:f00:80:f7:1111::6ade/124"));
set.add(new IpPrefix("f00b:a33::/112"));
assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
NetworkUtils.routedIPv6AddressCount(set));
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2020 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 android.net;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@RunWith(AndroidJUnit4.class)
@androidx.test.filters.SmallTest
public class QosSocketFilterTest {
@Test
public void testPortExactMatch() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
assertTrue(QosSocketFilter.matchesLocalAddress(
new InetSocketAddress(addressA, 10), addressB, 10, 10));
}
@Test
public void testPortLessThanStart() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
assertFalse(QosSocketFilter.matchesLocalAddress(
new InetSocketAddress(addressA, 8), addressB, 10, 10));
}
@Test
public void testPortGreaterThanEnd() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
assertFalse(QosSocketFilter.matchesLocalAddress(
new InetSocketAddress(addressA, 18), addressB, 10, 10));
}
@Test
public void testPortBetweenStartAndEnd() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
assertTrue(QosSocketFilter.matchesLocalAddress(
new InetSocketAddress(addressA, 10), addressB, 8, 18));
}
@Test
public void testAddressesDontMatch() {
final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.5");
assertFalse(QosSocketFilter.matchesLocalAddress(
new InetSocketAddress(addressA, 10), addressB, 10, 10));
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2018 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 android.net;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.net.wifi.WifiNetworkSpecifier;
import android.telephony.SubscriptionManager;
import androidx.test.filters.SmallTest;
import org.junit.Test;
/**
* Unit test for {@link android.net.TelephonyNetworkSpecifier}.
*/
@SmallTest
public class TelephonyNetworkSpecifierTest {
private static final int TEST_SUBID = 5;
private static final String TEST_SSID = "Test123";
/**
* Validate that IllegalArgumentException will be thrown if build TelephonyNetworkSpecifier
* without calling {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
*/
@Test
public void testBuilderBuildWithDefault() {
try {
new TelephonyNetworkSpecifier.Builder().build();
} catch (IllegalArgumentException iae) {
// expected, test pass
}
}
/**
* Validate that no exception will be thrown even if pass invalid subscription id to
* {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
*/
@Test
public void testBuilderBuildWithInvalidSubId() {
TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
.build();
assertEquals(specifier.getSubscriptionId(), SubscriptionManager.INVALID_SUBSCRIPTION_ID);
}
/**
* Validate the correctness of TelephonyNetworkSpecifier when provide valid subId.
*/
@Test
public void testBuilderBuildWithValidSubId() {
final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(TEST_SUBID)
.build();
assertEquals(TEST_SUBID, specifier.getSubscriptionId());
}
/**
* Validate that parcel marshalling/unmarshalling works.
*/
@Test
public void testParcel() {
TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(TEST_SUBID)
.build();
assertParcelSane(specifier, 1 /* fieldCount */);
}
/**
* Validate the behavior of method canBeSatisfiedBy().
*/
@Test
public void testCanBeSatisfiedBy() {
final TelephonyNetworkSpecifier tns1 = new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(TEST_SUBID)
.build();
final TelephonyNetworkSpecifier tns2 = new TelephonyNetworkSpecifier.Builder()
.setSubscriptionId(TEST_SUBID)
.build();
final WifiNetworkSpecifier wns = new WifiNetworkSpecifier.Builder()
.setSsid(TEST_SSID)
.build();
final MatchAllNetworkSpecifier mans = new MatchAllNetworkSpecifier();
// Test equality
assertEquals(tns1, tns2);
assertTrue(tns1.canBeSatisfiedBy(tns1));
assertTrue(tns1.canBeSatisfiedBy(tns2));
// Test other edge cases.
assertFalse(tns1.canBeSatisfiedBy(null));
assertFalse(tns1.canBeSatisfiedBy(wns));
assertTrue(tns1.canBeSatisfiedBy(mans));
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2019 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 android.net;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Intent;
import android.test.mock.MockContext;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.MessageUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link VpnManager}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class VpnManagerTest {
private static final String PKG_NAME = "fooPackage";
private static final String SESSION_NAME_STRING = "testSession";
private static final String SERVER_ADDR_STRING = "1.2.3.4";
private static final String IDENTITY_STRING = "Identity";
private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
private IVpnManager mMockService;
private VpnManager mVpnManager;
private final MockContext mMockContext =
new MockContext() {
@Override
public String getOpPackageName() {
return PKG_NAME;
}
};
@Before
public void setUp() throws Exception {
mMockService = mock(IVpnManager.class);
mVpnManager = new VpnManager(mMockContext, mMockService);
}
@Test
public void testProvisionVpnProfilePreconsented() throws Exception {
final PlatformVpnProfile profile = getPlatformVpnProfile();
when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
.thenReturn(true);
// Expect there to be no intent returned, as consent has already been granted.
assertNull(mVpnManager.provisionVpnProfile(profile));
verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
}
@Test
public void testProvisionVpnProfileNeedsConsent() throws Exception {
final PlatformVpnProfile profile = getPlatformVpnProfile();
when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
.thenReturn(false);
// Expect intent to be returned, as consent has not already been granted.
final Intent intent = mVpnManager.provisionVpnProfile(profile);
assertNotNull(intent);
final ComponentName expectedComponentName =
ComponentName.unflattenFromString(
"com.android.vpndialogs/com.android.vpndialogs.PlatformVpnConfirmDialog");
assertEquals(expectedComponentName, intent.getComponent());
verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
}
@Test
public void testDeleteProvisionedVpnProfile() throws Exception {
mVpnManager.deleteProvisionedVpnProfile();
verify(mMockService).deleteVpnProfile(eq(PKG_NAME));
}
@Test
public void testStartProvisionedVpnProfile() throws Exception {
mVpnManager.startProvisionedVpnProfile();
verify(mMockService).startVpnProfile(eq(PKG_NAME));
}
@Test
public void testStopProvisionedVpnProfile() throws Exception {
mVpnManager.stopProvisionedVpnProfile();
verify(mMockService).stopVpnProfile(eq(PKG_NAME));
}
private Ikev2VpnProfile getPlatformVpnProfile() throws Exception {
return new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING)
.setBypassable(true)
.setMaxMtu(1300)
.setMetered(true)
.setAuthPsk(PSK_BYTES)
.build();
}
@Test
public void testVpnTypesEqual() throws Exception {
SparseArray<String> vmVpnTypes = MessageUtils.findMessageNames(
new Class[] { VpnManager.class }, new String[]{ "TYPE_VPN_" });
SparseArray<String> nativeVpnType = MessageUtils.findMessageNames(
new Class[] { NativeVpnType.class }, new String[]{ "" });
// TYPE_VPN_NONE = -1 is only defined in VpnManager.
assertEquals(vmVpnTypes.size() - 1, nativeVpnType.size());
for (int i = VpnManager.TYPE_VPN_SERVICE; i < vmVpnTypes.size(); i++) {
assertEquals(vmVpnTypes.get(i), "TYPE_VPN_" + nativeVpnType.get(i));
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2021 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 android.net;
import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.REDACT_NONE;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class VpnTransportInfoTest {
@Test
public void testParceling() {
VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345");
assertParcelSane(v, 2 /* fieldCount */);
}
@Test
public void testEqualsAndHashCode() {
String session1 = "12345";
String session2 = "6789";
VpnTransportInfo v11 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
VpnTransportInfo v12 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE, session1);
VpnTransportInfo v13 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
VpnTransportInfo v14 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session1);
VpnTransportInfo v15 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1);
VpnTransportInfo v21 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session2);
VpnTransportInfo v31 = v11.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
VpnTransportInfo v32 = v13.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
assertNotEquals(v11, v12);
assertNotEquals(v13, v14);
assertNotEquals(v14, v15);
assertNotEquals(v14, v21);
assertEquals(v11, v13);
assertEquals(v31, v32);
assertEquals(v11.hashCode(), v13.hashCode());
assertEquals(REDACT_FOR_NETWORK_SETTINGS, v32.getApplicableRedactions());
assertEquals(session1, v15.makeCopy(REDACT_NONE).getSessionId());
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2018 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 android.net.ipmemorystore;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirk;
import android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirkParcelable;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.reflect.Modifier;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Collections;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ParcelableTests {
@Test
public void testNetworkAttributesParceling() throws Exception {
final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
NetworkAttributes in = builder.build();
assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
// lease will expire in two hours
builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
// cluster stays null this time around
builder.setDnsAddresses(Collections.emptyList());
builder.setMtu(18);
in = builder.build();
assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9"));
builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000);
builder.setCluster("groupHint");
builder.setDnsAddresses(Arrays.asList(
InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"),
InetAddress.getByName("6.7.8.9")));
builder.setMtu(1_000_000);
in = builder.build();
assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
builder.setMtu(null);
in = builder.build();
assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
// Verify that this test does not miss any new field added later.
// If any field is added to NetworkAttributes it must be tested here for parceling
// roundtrip.
assertEquals(6, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
.filter(f -> !Modifier.isStatic(f.getModifiers())).count());
}
@Test
public void testPrivateDataParceling() throws Exception {
final Blob in = new Blob();
in.data = new byte[] {89, 111, 108, 111};
final Blob out = parcelingRoundTrip(in);
// Object.equals on byte[] tests the references
assertEquals(in.data.length, out.data.length);
assertTrue(Arrays.equals(in.data, out.data));
}
@Test
public void testSameL3NetworkResponseParceling() throws Exception {
final SameL3NetworkResponseParcelable parcelable = new SameL3NetworkResponseParcelable();
parcelable.l2Key1 = "key 1";
parcelable.l2Key2 = "key 2";
parcelable.confidence = 0.43f;
final SameL3NetworkResponse in = new SameL3NetworkResponse(parcelable);
assertEquals("key 1", in.l2Key1);
assertEquals("key 2", in.l2Key2);
assertEquals(0.43f, in.confidence, 0.01f /* delta */);
final SameL3NetworkResponse out =
new SameL3NetworkResponse(parcelingRoundTrip(in.toParcelable()));
assertEquals(in, out);
assertEquals(in.l2Key1, out.l2Key1);
assertEquals(in.l2Key2, out.l2Key2);
assertEquals(in.confidence, out.confidence, 0.01f /* delta */);
}
@Test
public void testIPv6ProvisioningLossQuirkParceling() throws Exception {
final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
final IPv6ProvisioningLossQuirkParcelable parcelable =
new IPv6ProvisioningLossQuirkParcelable();
final long expiry = System.currentTimeMillis() + 7_200_000;
parcelable.detectionCount = 3;
parcelable.quirkExpiry = expiry; // quirk info will expire in two hours
builder.setIpv6ProvLossQuirk(IPv6ProvisioningLossQuirk.fromStableParcelable(parcelable));
final NetworkAttributes in = builder.build();
final NetworkAttributes out = new NetworkAttributes(parcelingRoundTrip(in.toParcelable()));
assertEquals(out.ipv6ProvisioningLossQuirk, in.ipv6ProvisioningLossQuirk);
}
private <T extends Parcelable> T parcelingRoundTrip(final T in) throws Exception {
final Parcel p = Parcel.obtain();
in.writeToParcel(p, /* flags */ 0);
p.setDataPosition(0);
final byte[] marshalledData = p.marshall();
p.recycle();
final Parcel q = Parcel.obtain();
q.unmarshall(marshalledData, 0, marshalledData.length);
q.setDataPosition(0);
final Parcelable.Creator<T> creator = (Parcelable.Creator<T>)
in.getClass().getField("CREATOR").get(null); // static object, so null receiver
final T unmarshalled = (T) creator.createFromParcel(q);
q.recycle();
return unmarshalled;
}
}

View File

@@ -0,0 +1,388 @@
/*
* Copyright (C) 2017 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 android.net.nsd;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.AsyncChannel;
import com.android.testutils.HandlerUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NsdManagerTest {
static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
@Mock Context mContext;
@Mock INsdManager mService;
MockServiceHandler mServiceHandler;
NsdManager mManager;
long mTimeoutMs = 200; // non-final so that tests can adjust the value.
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mServiceHandler = spy(MockServiceHandler.create(mContext));
when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
mManager = makeManager();
}
@After
public void tearDown() throws Exception {
HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
mServiceHandler.chan.disconnect();
mServiceHandler.stop();
if (mManager != null) {
mManager.disconnect();
}
}
@Test
public void testResolveService() {
NsdManager manager = mManager;
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
manager.resolveService(request, listener);
int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
int err = 33;
sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
manager.resolveService(request, listener);
int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
}
@Test
public void testParallelResolveService() {
NsdManager manager = mManager;
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
NsdManager.ResolveListener listener1 = mock(NsdManager.ResolveListener.class);
NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
manager.resolveService(request, listener1);
int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
manager.resolveService(request, listener2);
int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
}
@Test
public void testRegisterService() {
NsdManager manager = mManager;
NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
NsdServiceInfo request2 = new NsdServiceInfo("another_name", "another_type");
request1.setPort(2201);
request2.setPort(2202);
NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
NsdManager.RegistrationListener listener2 = mock(NsdManager.RegistrationListener.class);
// Register two services
manager.registerService(request1, PROTOCOL, listener1);
int key1 = verifyRequest(NsdManager.REGISTER_SERVICE);
manager.registerService(request2, PROTOCOL, listener2);
int key2 = verifyRequest(NsdManager.REGISTER_SERVICE);
// First reques fails, second request succeeds
sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key2, request2);
verify(listener2, timeout(mTimeoutMs).times(1)).onServiceRegistered(request2);
int err = 1;
sendResponse(NsdManager.REGISTER_SERVICE_FAILED, err, key1, request1);
verify(listener1, timeout(mTimeoutMs).times(1)).onRegistrationFailed(request1, err);
// Client retries first request, it succeeds
manager.registerService(request1, PROTOCOL, listener1);
int key3 = verifyRequest(NsdManager.REGISTER_SERVICE);
sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key3, request1);
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceRegistered(request1);
// First request is unregistered, it succeeds
manager.unregisterService(listener1);
int key3again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
assertEquals(key3, key3again);
sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key3again, null);
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request1);
// Second request is unregistered, it fails
manager.unregisterService(listener2);
int key2again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
assertEquals(key2, key2again);
sendResponse(NsdManager.UNREGISTER_SERVICE_FAILED, err, key2again, null);
verify(listener2, timeout(mTimeoutMs).times(1)).onUnregistrationFailed(request2, err);
// TODO: do not unregister listener until service is unregistered
// Client retries unregistration of second request, it succeeds
//manager.unregisterService(listener2);
//int key2yetAgain = verifyRequest(NsdManager.UNREGISTER_SERVICE);
//assertEquals(key2, key2yetAgain);
//sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key2yetAgain, null);
//verify(listener2, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request2);
}
@Test
public void testDiscoverService() {
NsdManager manager = mManager;
NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
NsdServiceInfo reply2 = new NsdServiceInfo("another_name", "a_type");
NsdServiceInfo reply3 = new NsdServiceInfo("a_third_name", "a_type");
NsdManager.DiscoveryListener listener = mock(NsdManager.DiscoveryListener.class);
// Client registers for discovery, request fails
manager.discoverServices("a_type", PROTOCOL, listener);
int key1 = verifyRequest(NsdManager.DISCOVER_SERVICES);
int err = 1;
sendResponse(NsdManager.DISCOVER_SERVICES_FAILED, err, key1, null);
verify(listener, timeout(mTimeoutMs).times(1)).onStartDiscoveryFailed("a_type", err);
// Client retries, request succeeds
manager.discoverServices("a_type", PROTOCOL, listener);
int key2 = verifyRequest(NsdManager.DISCOVER_SERVICES);
sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key2, reply1);
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
// mdns notifies about services
sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply1);
verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply1);
sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply2);
verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply2);
sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply2);
verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply2);
// Client unregisters its listener
manager.stopServiceDiscovery(listener);
int key2again = verifyRequest(NsdManager.STOP_DISCOVERY);
assertEquals(key2, key2again);
// TODO: unregister listener immediately and stop notifying it about services
// Notifications are still passed to the client's listener
sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply1);
verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply1);
// Client is notified of complete unregistration
sendResponse(NsdManager.STOP_DISCOVERY_SUCCEEDED, 0, key2again, "a_type");
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStopped("a_type");
// Notifications are not passed to the client anymore
sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply3);
verify(listener, timeout(mTimeoutMs).times(0)).onServiceLost(reply3);
// Client registers for service discovery
reset(listener);
manager.discoverServices("a_type", PROTOCOL, listener);
int key3 = verifyRequest(NsdManager.DISCOVER_SERVICES);
sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key3, reply1);
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
// Client unregisters immediately, it fails
manager.stopServiceDiscovery(listener);
int key3again = verifyRequest(NsdManager.STOP_DISCOVERY);
assertEquals(key3, key3again);
err = 2;
sendResponse(NsdManager.STOP_DISCOVERY_FAILED, err, key3again, "a_type");
verify(listener, timeout(mTimeoutMs).times(1)).onStopDiscoveryFailed("a_type", err);
// New notifications are not passed to the client anymore
sendResponse(NsdManager.SERVICE_FOUND, 0, key3, reply1);
verify(listener, timeout(mTimeoutMs).times(0)).onServiceFound(reply1);
}
@Test
public void testInvalidCalls() {
NsdManager manager = mManager;
NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
NsdServiceInfo invalidService = new NsdServiceInfo(null, null);
NsdServiceInfo validService = new NsdServiceInfo("a_name", "a_type");
validService.setPort(2222);
// Service registration
// - invalid arguments
mustFail(() -> { manager.unregisterService(null); });
mustFail(() -> { manager.registerService(null, -1, null); });
mustFail(() -> { manager.registerService(null, PROTOCOL, listener1); });
mustFail(() -> { manager.registerService(invalidService, PROTOCOL, listener1); });
mustFail(() -> { manager.registerService(validService, -1, listener1); });
mustFail(() -> { manager.registerService(validService, PROTOCOL, null); });
manager.registerService(validService, PROTOCOL, listener1);
// - listener already registered
mustFail(() -> { manager.registerService(validService, PROTOCOL, listener1); });
manager.unregisterService(listener1);
// TODO: make listener immediately reusable
//mustFail(() -> { manager.unregisterService(listener1); });
//manager.registerService(validService, PROTOCOL, listener1);
// Discover service
// - invalid arguments
mustFail(() -> { manager.stopServiceDiscovery(null); });
mustFail(() -> { manager.discoverServices(null, -1, null); });
mustFail(() -> { manager.discoverServices(null, PROTOCOL, listener2); });
mustFail(() -> { manager.discoverServices("a_service", -1, listener2); });
mustFail(() -> { manager.discoverServices("a_service", PROTOCOL, null); });
manager.discoverServices("a_service", PROTOCOL, listener2);
// - listener already registered
mustFail(() -> { manager.discoverServices("another_service", PROTOCOL, listener2); });
manager.stopServiceDiscovery(listener2);
// TODO: make listener immediately reusable
//mustFail(() -> { manager.stopServiceDiscovery(listener2); });
//manager.discoverServices("another_service", PROTOCOL, listener2);
// Resolver service
// - invalid arguments
mustFail(() -> { manager.resolveService(null, null); });
mustFail(() -> { manager.resolveService(null, listener3); });
mustFail(() -> { manager.resolveService(invalidService, listener3); });
mustFail(() -> { manager.resolveService(validService, null); });
manager.resolveService(validService, listener3);
// - listener already registered:w
mustFail(() -> { manager.resolveService(validService, listener3); });
}
public void mustFail(Runnable fn) {
try {
fn.run();
fail();
} catch (Exception expected) {
}
}
NsdManager makeManager() {
NsdManager manager = new NsdManager(mContext, mService);
// Acknowledge first two messages connecting the AsyncChannel.
verify(mServiceHandler, timeout(mTimeoutMs).times(2)).handleMessage(any());
reset(mServiceHandler);
assertNotNull(mServiceHandler.chan);
return manager;
}
int verifyRequest(int expectedMessageType) {
HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
reset(mServiceHandler);
Message received = mServiceHandler.getLastMessage();
assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
return received.arg2;
}
void sendResponse(int replyType, int arg, int key, Object obj) {
mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
}
// Implements the server side of AsyncChannel connection protocol
public static class MockServiceHandler extends Handler {
public final Context context;
public AsyncChannel chan;
public Message lastMessage;
MockServiceHandler(Looper l, Context c) {
super(l);
context = c;
}
synchronized Message getLastMessage() {
return lastMessage;
}
synchronized void setLastMessage(Message msg) {
lastMessage = obtainMessage();
lastMessage.copyFrom(msg);
}
@Override
public void handleMessage(Message msg) {
setLastMessage(msg);
if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
chan = new AsyncChannel();
chan.connect(context, this, msg.replyTo);
chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
}
}
void stop() {
getLooper().quitSafely();
}
static MockServiceHandler create(Context context) {
HandlerThread t = new HandlerThread("mock-service-handler");
t.start();
return new MockServiceHandler(t.getLooper(), context);
}
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (C) 2014 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 android.net.nsd;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.os.Bundle;
import android.os.Parcel;
import android.os.StrictMode;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Map;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NsdServiceInfoTest {
public final static InetAddress LOCALHOST;
static {
// Because test.
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
InetAddress _host = null;
try {
_host = InetAddress.getLocalHost();
} catch (UnknownHostException e) { }
LOCALHOST = _host;
}
@Test
public void testLimits() throws Exception {
NsdServiceInfo info = new NsdServiceInfo();
// Non-ASCII keys.
boolean exceptionThrown = false;
try {
info.setAttribute("", "meow");
} catch (IllegalArgumentException e) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
assertEmptyServiceInfo(info);
// ASCII keys with '=' character.
exceptionThrown = false;
try {
info.setAttribute("kitten=", "meow");
} catch (IllegalArgumentException e) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
assertEmptyServiceInfo(info);
// Single key + value length too long.
exceptionThrown = false;
try {
String longValue = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
"ooooooooooooooooooooooooooooong"; // 248 characters.
info.setAttribute("longcat", longValue); // Key + value == 255 characters.
} catch (IllegalArgumentException e) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
assertEmptyServiceInfo(info);
// Total TXT record length too long.
exceptionThrown = false;
int recordsAdded = 0;
try {
for (int i = 100; i < 300; ++i) {
// 6 char key + 5 char value + 2 bytes overhead = 13 byte record length.
String key = String.format("key%d", i);
info.setAttribute(key, "12345");
recordsAdded++;
}
} catch (IllegalArgumentException e) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
assertTrue(100 == recordsAdded);
assertTrue(info.getTxtRecord().length == 1300);
}
@Test
public void testParcel() throws Exception {
NsdServiceInfo emptyInfo = new NsdServiceInfo();
checkParcelable(emptyInfo);
NsdServiceInfo fullInfo = new NsdServiceInfo();
fullInfo.setServiceName("kitten");
fullInfo.setServiceType("_kitten._tcp");
fullInfo.setPort(4242);
fullInfo.setHost(LOCALHOST);
checkParcelable(fullInfo);
NsdServiceInfo noHostInfo = new NsdServiceInfo();
noHostInfo.setServiceName("kitten");
noHostInfo.setServiceType("_kitten._tcp");
noHostInfo.setPort(4242);
checkParcelable(noHostInfo);
NsdServiceInfo attributedInfo = new NsdServiceInfo();
attributedInfo.setServiceName("kitten");
attributedInfo.setServiceType("_kitten._tcp");
attributedInfo.setPort(4242);
attributedInfo.setHost(LOCALHOST);
attributedInfo.setAttribute("color", "pink");
attributedInfo.setAttribute("sound", (new String("にゃあ")).getBytes("UTF-8"));
attributedInfo.setAttribute("adorable", (String) null);
attributedInfo.setAttribute("sticky", "yes");
attributedInfo.setAttribute("siblings", new byte[] {});
attributedInfo.setAttribute("edge cases", new byte[] {0, -1, 127, -128});
attributedInfo.removeAttribute("sticky");
checkParcelable(attributedInfo);
// Sanity check that we actually wrote attributes to attributedInfo.
assertTrue(attributedInfo.getAttributes().keySet().contains("adorable"));
String sound = new String(attributedInfo.getAttributes().get("sound"), "UTF-8");
assertTrue(sound.equals("にゃあ"));
byte[] edgeCases = attributedInfo.getAttributes().get("edge cases");
assertTrue(Arrays.equals(edgeCases, new byte[] {0, -1, 127, -128}));
assertFalse(attributedInfo.getAttributes().keySet().contains("sticky"));
}
public void checkParcelable(NsdServiceInfo original) {
// Write to parcel.
Parcel p = Parcel.obtain();
Bundle writer = new Bundle();
writer.putParcelable("test_info", original);
writer.writeToParcel(p, 0);
// Extract from parcel.
p.setDataPosition(0);
Bundle reader = p.readBundle();
reader.setClassLoader(NsdServiceInfo.class.getClassLoader());
NsdServiceInfo result = reader.getParcelable("test_info");
// Assert equality of base fields.
assertEquals(original.getServiceName(), result.getServiceName());
assertEquals(original.getServiceType(), result.getServiceType());
assertEquals(original.getHost(), result.getHost());
assertTrue(original.getPort() == result.getPort());
// Assert equality of attribute map.
Map<String, byte[]> originalMap = original.getAttributes();
Map<String, byte[]> resultMap = result.getAttributes();
assertEquals(originalMap.keySet(), resultMap.keySet());
for (String key : originalMap.keySet()) {
assertTrue(Arrays.equals(originalMap.get(key), resultMap.get(key)));
}
}
public void assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty) {
byte[] txtRecord = shouldBeEmpty.getTxtRecord();
if (txtRecord == null || txtRecord.length == 0) {
return;
}
fail("NsdServiceInfo.getTxtRecord did not return null but " + Arrays.toString(txtRecord));
}
}

View File

@@ -0,0 +1,216 @@
/*
* Copyright (C) 2019 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 android.net.util;
import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_GLOBAL;
import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_LINKLOCAL;
import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_SITELOCAL;
import static org.junit.Assert.assertEquals;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.InetAddresses;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DnsUtilsTest {
private InetAddress stringToAddress(@NonNull String addr) {
return InetAddresses.parseNumericAddress(addr);
}
private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr) {
return makeSortableAddress(addr, null);
}
private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr,
@Nullable String srcAddr) {
return new DnsUtils.SortableAddress(stringToAddress(addr),
srcAddr != null ? stringToAddress(srcAddr) : null);
}
@Test
public void testRfc6724Comparator() {
final List<DnsUtils.SortableAddress> test = Arrays.asList(
// Ipv4
makeSortableAddress("216.58.200.36", "192.168.1.1"),
// global with different scope src
makeSortableAddress("2404:6800:4008:801::2004", "fe80::1111:2222"),
// global without src addr
makeSortableAddress("2404:6800:cafe:801::1"),
// loop back
makeSortableAddress("::1", "::1"),
// link local
makeSortableAddress("fe80::c46f:1cff:fe04:39b4", "fe80::1"),
// teredo tunneling
makeSortableAddress("2001::47c1", "2001::2"),
// 6bone without src addr
makeSortableAddress("3ffe::1234:5678"),
// IPv4-compatible
makeSortableAddress("::216.58.200.36", "::216.58.200.9"),
// 6bone
makeSortableAddress("3ffe::1234:5678", "3ffe::1234:1"),
// IPv4-mapped IPv6
makeSortableAddress("::ffff:192.168.95.7", "::ffff:192.168.95.1"));
final List<InetAddress> expected = Arrays.asList(
stringToAddress("::1"), // loop back
stringToAddress("fe80::c46f:1cff:fe04:39b4"), // link local
stringToAddress("216.58.200.36"), // Ipv4
stringToAddress("::ffff:192.168.95.7"), // IPv4-mapped IPv6
stringToAddress("2001::47c1"), // teredo tunneling
stringToAddress("::216.58.200.36"), // IPv4-compatible
stringToAddress("3ffe::1234:5678"), // 6bone
stringToAddress("2404:6800:4008:801::2004"), // global with different scope src
stringToAddress("2404:6800:cafe:801::1"), // global without src addr
stringToAddress("3ffe::1234:5678")); // 6bone without src addr
Collections.sort(test, new DnsUtils.Rfc6724Comparator());
for (int i = 0; i < test.size(); ++i) {
assertEquals(test.get(i).address, expected.get(i));
}
// TODO: add more combinations
}
@Test
public void testV4SortableAddress() {
// Test V4 address
DnsUtils.SortableAddress test = makeSortableAddress("216.58.200.36");
assertEquals(test.hasSrcAddr, 0);
assertEquals(test.prefixMatchLen, 0);
assertEquals(test.address, stringToAddress("216.58.200.36"));
assertEquals(test.labelMatch, 0);
assertEquals(test.scopeMatch, 0);
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
assertEquals(test.label, 4);
assertEquals(test.precedence, 35);
// Test V4 loopback address with the same source address
test = makeSortableAddress("127.1.2.3", "127.1.2.3");
assertEquals(test.hasSrcAddr, 1);
assertEquals(test.prefixMatchLen, 0);
assertEquals(test.address, stringToAddress("127.1.2.3"));
assertEquals(test.labelMatch, 1);
assertEquals(test.scopeMatch, 1);
assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
assertEquals(test.label, 4);
assertEquals(test.precedence, 35);
}
@Test
public void testV6SortableAddress() {
// Test global address
DnsUtils.SortableAddress test = makeSortableAddress("2404:6800:4008:801::2004");
assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004"));
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
assertEquals(test.label, 1);
assertEquals(test.precedence, 40);
// Test global address with global source address
test = makeSortableAddress("2404:6800:4008:801::2004",
"2401:fa00:fc:fd00:6d6c:7199:b8e7:41d6");
assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004"));
assertEquals(test.hasSrcAddr, 1);
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
assertEquals(test.labelMatch, 1);
assertEquals(test.scopeMatch, 1);
assertEquals(test.label, 1);
assertEquals(test.precedence, 40);
assertEquals(test.prefixMatchLen, 13);
// Test global address with linklocal source address
test = makeSortableAddress("2404:6800:4008:801::2004", "fe80::c46f:1cff:fe04:39b4");
assertEquals(test.hasSrcAddr, 1);
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
assertEquals(test.labelMatch, 1);
assertEquals(test.scopeMatch, 0);
assertEquals(test.label, 1);
assertEquals(test.precedence, 40);
assertEquals(test.prefixMatchLen, 0);
// Test loopback address with the same source address
test = makeSortableAddress("::1", "::1");
assertEquals(test.hasSrcAddr, 1);
assertEquals(test.prefixMatchLen, 16 * 8);
assertEquals(test.labelMatch, 1);
assertEquals(test.scopeMatch, 1);
assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
assertEquals(test.label, 0);
assertEquals(test.precedence, 50);
// Test linklocal address
test = makeSortableAddress("fe80::c46f:1cff:fe04:39b4");
assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
assertEquals(test.label, 1);
assertEquals(test.precedence, 40);
// Test linklocal address
test = makeSortableAddress("fe80::");
assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
assertEquals(test.label, 1);
assertEquals(test.precedence, 40);
// Test 6to4 address
test = makeSortableAddress("2002:c000:0204::");
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
assertEquals(test.label, 2);
assertEquals(test.precedence, 30);
// Test unique local address
test = makeSortableAddress("fc00::c000:13ab");
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
assertEquals(test.label, 13);
assertEquals(test.precedence, 3);
// Test teredo tunneling address
test = makeSortableAddress("2001::47c1");
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
assertEquals(test.label, 5);
assertEquals(test.precedence, 5);
// Test IPv4-compatible addresses
test = makeSortableAddress("::216.58.200.36");
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
assertEquals(test.label, 3);
assertEquals(test.precedence, 1);
// Test site-local address
test = makeSortableAddress("fec0::cafe:3ab2");
assertEquals(test.scope, IPV6_ADDR_SCOPE_SITELOCAL);
assertEquals(test.label, 11);
assertEquals(test.precedence, 1);
// Test 6bone address
test = makeSortableAddress("3ffe::1234:5678");
assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
assertEquals(test.label, 12);
assertEquals(test.precedence, 1);
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2019 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 android.net.util
import android.content.Context
import android.content.res.Resources
import android.net.ConnectivityResources
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.MAX_TRANSPORT
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
import android.net.NetworkCapabilities.TRANSPORT_VPN
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import androidx.test.filters.SmallTest
import com.android.internal.R
import org.junit.After
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.any
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
/**
* Tests for [KeepaliveUtils].
*
* Build, install and run with:
* atest android.net.util.KeepaliveUtilsTest
*/
@RunWith(JUnit4::class)
@SmallTest
class KeepaliveUtilsTest {
// Prepare mocked context with given resource strings.
private fun getMockedContextWithStringArrayRes(
id: Int,
name: String,
res: Array<out String?>?
): Context {
val mockRes = mock(Resources::class.java)
doReturn(res).`when`(mockRes).getStringArray(eq(id))
doReturn(id).`when`(mockRes).getIdentifier(eq(name), any(), any())
return mock(Context::class.java).apply {
doReturn(mockRes).`when`(this).getResources()
ConnectivityResources.setResourcesContextForTest(this)
}
}
@After
fun tearDown() {
ConnectivityResources.setResourcesContextForTest(null)
}
@Test
fun testGetSupportedKeepalives() {
fun assertRunWithException(res: Array<out String?>?) {
try {
val mockContext = getMockedContextWithStringArrayRes(
R.array.config_networkSupportedKeepaliveCount,
"config_networkSupportedKeepaliveCount", res)
KeepaliveUtils.getSupportedKeepalives(mockContext)
fail("Expected KeepaliveDeviceConfigurationException")
} catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) {
}
}
// Check resource with various invalid format.
assertRunWithException(null)
assertRunWithException(arrayOf<String?>(null))
assertRunWithException(arrayOfNulls<String?>(10))
assertRunWithException(arrayOf(""))
assertRunWithException(arrayOf("3,ABC"))
assertRunWithException(arrayOf("6,3,3"))
assertRunWithException(arrayOf("5"))
// Check resource with invalid slots value.
assertRunWithException(arrayOf("3,-1"))
// Check resource with invalid transport type.
assertRunWithException(arrayOf("-1,3"))
assertRunWithException(arrayOf("10,3"))
// Check valid customization generates expected array.
val validRes = arrayOf("0,3", "1,0", "4,4")
val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0)
val mockContext = getMockedContextWithStringArrayRes(
R.array.config_networkSupportedKeepaliveCount,
"config_networkSupportedKeepaliveCount", validRes)
val actual = KeepaliveUtils.getSupportedKeepalives(mockContext)
assertArrayEquals(expectedValidRes, actual)
}
@Test
fun testGetSupportedKeepalivesForNetworkCapabilities() {
// Mock customized supported keepalives for each transport type, and assuming:
// 3 for cellular,
// 6 for wifi,
// 0 for others.
val cust = IntArray(MAX_TRANSPORT + 1).apply {
this[TRANSPORT_CELLULAR] = 3
this[TRANSPORT_WIFI] = 6
}
val nc = NetworkCapabilities()
// Check supported keepalives with single transport type.
nc.transportTypes = intArrayOf(TRANSPORT_CELLULAR)
assertEquals(3, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
// Check supported keepalives with multiple transport types.
nc.transportTypes = intArrayOf(TRANSPORT_WIFI, TRANSPORT_VPN)
assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
// Check supported keepalives with non-customized transport type.
nc.transportTypes = intArrayOf(TRANSPORT_ETHERNET)
assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
// Check supported keepalives with undefined transport type.
nc.transportTypes = intArrayOf(MAX_TRANSPORT + 1)
try {
KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc)
fail("Expected ArrayIndexOutOfBoundsException")
} catch (expected: ArrayIndexOutOfBoundsException) {
}
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 2021 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 android.net.util
import android.content.Context
import android.content.res.Resources
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
import android.net.ConnectivityResources
import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI
import android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE
import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener
import android.provider.Settings
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import android.test.mock.MockContentResolver
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.connectivity.resources.R
import com.android.internal.util.test.FakeSettingsProvider
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.argThat
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.any
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
/**
* Tests for [MultinetworkPolicyTracker].
*
* Build, install and run with:
* atest android.net.util.MultinetworkPolicyTrackerTest
*/
@RunWith(AndroidJUnit4::class)
@SmallTest
class MultinetworkPolicyTrackerTest {
private val resources = mock(Resources::class.java).also {
doReturn(R.integer.config_networkAvoidBadWifi).`when`(it).getIdentifier(
eq("config_networkAvoidBadWifi"), eq("integer"), any())
doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi)
}
private val telephonyManager = mock(TelephonyManager::class.java)
private val subscriptionManager = mock(SubscriptionManager::class.java).also {
doReturn(null).`when`(it).getActiveSubscriptionInfo(anyInt())
}
private val resolver = MockContentResolver().apply {
addProvider(Settings.AUTHORITY, FakeSettingsProvider()) }
private val context = mock(Context::class.java).also {
doReturn(Context.TELEPHONY_SERVICE).`when`(it)
.getSystemServiceName(TelephonyManager::class.java)
doReturn(telephonyManager).`when`(it).getSystemService(Context.TELEPHONY_SERVICE)
doReturn(subscriptionManager).`when`(it)
.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
doReturn(resolver).`when`(it).contentResolver
doReturn(resources).`when`(it).resources
doReturn(it).`when`(it).createConfigurationContext(any())
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
ConnectivityResources.setResourcesContextForTest(it)
}
private val tracker = MultinetworkPolicyTracker(context, null /* handler */)
private fun assertMultipathPreference(preference: Int) {
Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
preference.toString())
tracker.updateMeteredMultipathPreference()
assertEquals(preference, tracker.meteredMultipathPreference)
}
@After
fun tearDown() {
ConnectivityResources.setResourcesContextForTest(null)
}
@Test
fun testUpdateMeteredMultipathPreference() {
assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER)
assertMultipathPreference(MULTIPATH_PREFERENCE_RELIABILITY)
assertMultipathPreference(MULTIPATH_PREFERENCE_PERFORMANCE)
}
@Test
fun testUpdateAvoidBadWifi() {
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
assertTrue(tracker.updateAvoidBadWifi())
assertFalse(tracker.avoidBadWifi)
doReturn(1).`when`(resources).getInteger(R.integer.config_networkAvoidBadWifi)
assertTrue(tracker.updateAvoidBadWifi())
assertTrue(tracker.avoidBadWifi)
}
@Test
fun testOnActiveDataSubscriptionIdChanged() {
val testSubId = 1000
val subscriptionInfo = SubscriptionInfo(testSubId, ""/* iccId */, 1/* iccId */,
"TMO"/* displayName */, "TMO"/* carrierName */, 1/* nameSource */, 1/* iconTint */,
"123"/* number */, 1/* roaming */, null/* icon */, "310"/* mcc */, "210"/* mnc */,
""/* countryIso */, false/* isEmbedded */, null/* nativeAccessRules */,
"1"/* cardString */)
doReturn(subscriptionInfo).`when`(subscriptionManager).getActiveSubscriptionInfo(testSubId)
// Modify avoidBadWifi and meteredMultipathPreference settings value and local variables in
// MultinetworkPolicyTracker should be also updated after subId changed.
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
MULTIPATH_PREFERENCE_PERFORMANCE.toString())
val listenerCaptor = ArgumentCaptor.forClass(
ActiveDataSubscriptionIdListener::class.java)
verify(telephonyManager, times(1))
.registerTelephonyCallback(any(), listenerCaptor.capture())
val listener = listenerCaptor.value
listener.onActiveDataSubscriptionIdChanged(testSubId)
// Check it get resource value with test sub id.
verify(subscriptionManager, times(1)).getActiveSubscriptionInfo(testSubId)
verify(context).createConfigurationContext(argThat { it.mcc == 310 && it.mnc == 210 })
// Check if avoidBadWifi and meteredMultipathPreference values have been updated.
assertFalse(tracker.avoidBadWifi)
assertEquals(MULTIPATH_PREFERENCE_PERFORMANCE, tracker.meteredMultipathPreference)
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2015 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.internal.net;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.AF_UNIX;
import static android.system.OsConstants.EPERM;
import static android.system.OsConstants.SOCK_DGRAM;
import static android.system.OsConstants.SOCK_STREAM;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.fail;
import android.system.ErrnoException;
import android.system.Os;
import androidx.test.runner.AndroidJUnit4;
import libcore.io.IoUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@androidx.test.filters.SmallTest
public class NetworkUtilsInternalTest {
private static void expectSocketSuccess(String msg, int domain, int type) {
try {
IoUtils.closeQuietly(Os.socket(domain, type, 0));
} catch (ErrnoException e) {
fail(msg + e.getMessage());
}
}
private static void expectSocketPemissionError(String msg, int domain, int type) {
try {
IoUtils.closeQuietly(Os.socket(domain, type, 0));
fail(msg);
} catch (ErrnoException e) {
assertEquals(msg, e.errno, EPERM);
}
}
private static void expectHasNetworking() {
expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
AF_UNIX, SOCK_STREAM);
expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
AF_INET, SOCK_DGRAM);
expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
AF_INET6, SOCK_DGRAM);
}
private static void expectNoNetworking() {
expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
AF_UNIX, SOCK_STREAM);
expectSocketPemissionError(
"Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
AF_INET, SOCK_DGRAM);
expectSocketPemissionError(
"Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
AF_INET6, SOCK_DGRAM);
}
@Test
public void testSetAllowNetworkingForProcess() {
expectHasNetworking();
NetworkUtilsInternal.setAllowNetworkingForProcess(false);
expectNoNetworking();
NetworkUtilsInternal.setAllowNetworkingForProcess(true);
expectHasNetworking();
}
}

View File

@@ -0,0 +1,218 @@
/*
* Copyright (C) 2019 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.internal.net;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.net.IpSecAlgorithm;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** Unit tests for {@link VpnProfile}. */
@SmallTest
@RunWith(JUnit4.class)
public class VpnProfileTest {
private static final String DUMMY_PROFILE_KEY = "Test";
private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23;
private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
@Test
public void testDefaults() throws Exception {
final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY);
assertEquals(DUMMY_PROFILE_KEY, p.key);
assertEquals("", p.name);
assertEquals(VpnProfile.TYPE_PPTP, p.type);
assertEquals("", p.server);
assertEquals("", p.username);
assertEquals("", p.password);
assertEquals("", p.dnsServers);
assertEquals("", p.searchDomains);
assertEquals("", p.routes);
assertTrue(p.mppe);
assertEquals("", p.l2tpSecret);
assertEquals("", p.ipsecIdentifier);
assertEquals("", p.ipsecSecret);
assertEquals("", p.ipsecUserCert);
assertEquals("", p.ipsecCaCert);
assertEquals("", p.ipsecServerCert);
assertEquals(null, p.proxy);
assertTrue(p.getAllowedAlgorithms() != null && p.getAllowedAlgorithms().isEmpty());
assertFalse(p.isBypassable);
assertFalse(p.isMetered);
assertEquals(1360, p.maxMtu);
assertFalse(p.areAuthParamsInline);
assertFalse(p.isRestrictedToTestNetworks);
}
private VpnProfile getSampleIkev2Profile(String key) {
final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */);
p.name = "foo";
p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
p.server = "bar";
p.username = "baz";
p.password = "qux";
p.dnsServers = "8.8.8.8";
p.searchDomains = "";
p.routes = "0.0.0.0/0";
p.mppe = false;
p.l2tpSecret = "";
p.ipsecIdentifier = "quux";
p.ipsecSecret = "quuz";
p.ipsecUserCert = "corge";
p.ipsecCaCert = "grault";
p.ipsecServerCert = "garply";
p.proxy = null;
p.setAllowedAlgorithms(
Arrays.asList(
IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
IpSecAlgorithm.AUTH_HMAC_SHA512,
IpSecAlgorithm.CRYPT_AES_CBC));
p.isBypassable = true;
p.isMetered = true;
p.maxMtu = 1350;
p.areAuthParamsInline = true;
// Not saved, but also not compared.
p.saveLogin = true;
return p;
}
@Test
public void testEquals() {
assertEquals(
getSampleIkev2Profile(DUMMY_PROFILE_KEY), getSampleIkev2Profile(DUMMY_PROFILE_KEY));
final VpnProfile modified = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
modified.maxMtu--;
assertNotEquals(getSampleIkev2Profile(DUMMY_PROFILE_KEY), modified);
}
@Test
public void testParcelUnparcel() {
assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23);
}
@Test
public void testSetInvalidAlgorithmValueDelimiter() {
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
try {
profile.setAllowedAlgorithms(
Arrays.asList("test" + VpnProfile.VALUE_DELIMITER + "test"));
fail("Expected failure due to value separator in algorithm name");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testSetInvalidAlgorithmListDelimiter() {
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
try {
profile.setAllowedAlgorithms(
Arrays.asList("test" + VpnProfile.LIST_DELIMITER + "test"));
fail("Expected failure due to value separator in algorithm name");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testEncodeDecode() {
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
assertEquals(profile, decoded);
}
@Test
public void testEncodeDecodeTooManyValues() {
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
final byte[] tooManyValues =
(new String(profile.encode()) + VpnProfile.VALUE_DELIMITER + "invalid").getBytes();
assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues));
}
private String getEncodedDecodedIkev2ProfileMissingValues(int... missingIndices) {
// Sort to ensure when we remove, we can do it from greatest first.
Arrays.sort(missingIndices);
final String encoded = new String(getSampleIkev2Profile(DUMMY_PROFILE_KEY).encode());
final List<String> parts =
new ArrayList<>(Arrays.asList(encoded.split(VpnProfile.VALUE_DELIMITER)));
// Remove from back first to ensure indexing is consistent.
for (int i = missingIndices.length - 1; i >= 0; i--) {
parts.remove(missingIndices[i]);
}
return String.join(VpnProfile.VALUE_DELIMITER, parts.toArray(new String[0]));
}
@Test
public void testEncodeDecodeInvalidNumberOfValues() {
final String tooFewValues =
getEncodedDecodedIkev2ProfileMissingValues(
ENCODED_INDEX_AUTH_PARAMS_INLINE,
ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
}
@Test
public void testEncodeDecodeMissingIsRestrictedToTestNetworks() {
final String tooFewValues =
getEncodedDecodedIkev2ProfileMissingValues(
ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
// Verify decoding without isRestrictedToTestNetworks defaults to false
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
assertFalse(decoded.isRestrictedToTestNetworks);
}
@Test
public void testEncodeDecodeLoginsNotSaved() {
final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
profile.saveLogin = false;
final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
assertNotEquals(profile, decoded);
// Add the username/password back, everything else must be equal.
decoded.username = profile.username;
decoded.password = profile.password;
assertEquals(profile, decoded);
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (C) 2017 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.internal.util;
import static com.android.internal.util.BitUtils.bytesToBEInt;
import static com.android.internal.util.BitUtils.bytesToLEInt;
import static com.android.internal.util.BitUtils.getUint16;
import static com.android.internal.util.BitUtils.getUint32;
import static com.android.internal.util.BitUtils.getUint8;
import static com.android.internal.util.BitUtils.packBits;
import static com.android.internal.util.BitUtils.uint16;
import static com.android.internal.util.BitUtils.uint32;
import static com.android.internal.util.BitUtils.uint8;
import static com.android.internal.util.BitUtils.unpackBits;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Random;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BitUtilsTest {
@Test
public void testUnsignedByteWideningConversions() {
byte b0 = 0;
byte b1 = 1;
byte bm1 = -1;
assertEquals(0, uint8(b0));
assertEquals(1, uint8(b1));
assertEquals(127, uint8(Byte.MAX_VALUE));
assertEquals(128, uint8(Byte.MIN_VALUE));
assertEquals(255, uint8(bm1));
assertEquals(255, uint8((byte)255));
}
@Test
public void testUnsignedShortWideningConversions() {
short s0 = 0;
short s1 = 1;
short sm1 = -1;
assertEquals(0, uint16(s0));
assertEquals(1, uint16(s1));
assertEquals(32767, uint16(Short.MAX_VALUE));
assertEquals(32768, uint16(Short.MIN_VALUE));
assertEquals(65535, uint16(sm1));
assertEquals(65535, uint16((short)65535));
}
@Test
public void testUnsignedShortComposition() {
byte b0 = 0;
byte b1 = 1;
byte b2 = 2;
byte b10 = 10;
byte b16 = 16;
byte b128 = -128;
byte b224 = -32;
byte b255 = -1;
assertEquals(0x0000, uint16(b0, b0));
assertEquals(0xffff, uint16(b255, b255));
assertEquals(0x0a01, uint16(b10, b1));
assertEquals(0x8002, uint16(b128, b2));
assertEquals(0x01ff, uint16(b1, b255));
assertEquals(0x80ff, uint16(b128, b255));
assertEquals(0xe010, uint16(b224, b16));
}
@Test
public void testUnsignedIntWideningConversions() {
assertEquals(0, uint32(0));
assertEquals(1, uint32(1));
assertEquals(2147483647L, uint32(Integer.MAX_VALUE));
assertEquals(2147483648L, uint32(Integer.MIN_VALUE));
assertEquals(4294967295L, uint32(-1));
assertEquals(4294967295L, uint32((int)4294967295L));
}
@Test
public void testBytesToInt() {
assertEquals(0x00000000, bytesToBEInt(bytes(0, 0, 0, 0)));
assertEquals(0xffffffff, bytesToBEInt(bytes(255, 255, 255, 255)));
assertEquals(0x0a000001, bytesToBEInt(bytes(10, 0, 0, 1)));
assertEquals(0x0a000002, bytesToBEInt(bytes(10, 0, 0, 2)));
assertEquals(0x0a001fff, bytesToBEInt(bytes(10, 0, 31, 255)));
assertEquals(0xe0000001, bytesToBEInt(bytes(224, 0, 0, 1)));
assertEquals(0x00000000, bytesToLEInt(bytes(0, 0, 0, 0)));
assertEquals(0x01020304, bytesToLEInt(bytes(4, 3, 2, 1)));
assertEquals(0xffff0000, bytesToLEInt(bytes(0, 0, 255, 255)));
}
@Test
public void testUnsignedGetters() {
ByteBuffer b = ByteBuffer.allocate(4);
b.putInt(0xffff);
assertEquals(0x0, getUint8(b, 0));
assertEquals(0x0, getUint8(b, 1));
assertEquals(0xff, getUint8(b, 2));
assertEquals(0xff, getUint8(b, 3));
assertEquals(0x0, getUint16(b, 0));
assertEquals(0xffff, getUint16(b, 2));
b.rewind();
b.putInt(0xffffffff);
assertEquals(0xffffffffL, getUint32(b, 0));
}
@Test
public void testBitsPacking() {
BitPackingTestCase[] testCases = {
new BitPackingTestCase(0, ints()),
new BitPackingTestCase(1, ints(0)),
new BitPackingTestCase(2, ints(1)),
new BitPackingTestCase(3, ints(0, 1)),
new BitPackingTestCase(4, ints(2)),
new BitPackingTestCase(6, ints(1, 2)),
new BitPackingTestCase(9, ints(0, 3)),
new BitPackingTestCase(~Long.MAX_VALUE, ints(63)),
new BitPackingTestCase(~Long.MAX_VALUE + 1, ints(0, 63)),
new BitPackingTestCase(~Long.MAX_VALUE + 2, ints(1, 63)),
};
for (BitPackingTestCase tc : testCases) {
int[] got = unpackBits(tc.packedBits);
assertTrue(
"unpackBits("
+ tc.packedBits
+ "): expected "
+ Arrays.toString(tc.bits)
+ " but got "
+ Arrays.toString(got),
Arrays.equals(tc.bits, got));
}
for (BitPackingTestCase tc : testCases) {
long got = packBits(tc.bits);
assertEquals(
"packBits("
+ Arrays.toString(tc.bits)
+ "): expected "
+ tc.packedBits
+ " but got "
+ got,
tc.packedBits,
got);
}
long[] moreTestCases = {
0, 1, -1, 23895, -908235, Long.MAX_VALUE, Long.MIN_VALUE, new Random().nextLong(),
};
for (long l : moreTestCases) {
assertEquals(l, packBits(unpackBits(l)));
}
}
static byte[] bytes(int b1, int b2, int b3, int b4) {
return new byte[] {b(b1), b(b2), b(b3), b(b4)};
}
static byte b(int i) {
return (byte) i;
}
static int[] ints(int... array) {
return array;
}
static class BitPackingTestCase {
final int[] bits;
final long packedBits;
BitPackingTestCase(long packedBits, int[] bits) {
this.bits = bits;
this.packedBits = packedBits;
}
}
}

View File

@@ -0,0 +1,178 @@
/*
* Copyright (C) 2017 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.internal.util;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class RingBufferTest {
@Test
public void testEmptyRingBuffer() {
RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
assertArrayEquals(new String[0], buffer.toArray());
}
@Test
public void testIncorrectConstructorArguments() {
try {
RingBuffer<String> buffer = new RingBuffer<>(String.class, -10);
fail("Should not be able to create a negative capacity RingBuffer");
} catch (IllegalArgumentException expected) {
}
try {
RingBuffer<String> buffer = new RingBuffer<>(String.class, 0);
fail("Should not be able to create a 0 capacity RingBuffer");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testRingBufferWithNoWrapping() {
RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
buffer.append("a");
buffer.append("b");
buffer.append("c");
buffer.append("d");
buffer.append("e");
String[] expected = {"a", "b", "c", "d", "e"};
assertArrayEquals(expected, buffer.toArray());
}
@Test
public void testRingBufferWithCapacity1() {
RingBuffer<String> buffer = new RingBuffer<>(String.class, 1);
buffer.append("a");
assertArrayEquals(new String[]{"a"}, buffer.toArray());
buffer.append("b");
assertArrayEquals(new String[]{"b"}, buffer.toArray());
buffer.append("c");
assertArrayEquals(new String[]{"c"}, buffer.toArray());
buffer.append("d");
assertArrayEquals(new String[]{"d"}, buffer.toArray());
buffer.append("e");
assertArrayEquals(new String[]{"e"}, buffer.toArray());
}
@Test
public void testRingBufferWithWrapping() {
int capacity = 100;
RingBuffer<String> buffer = new RingBuffer<>(String.class, capacity);
buffer.append("a");
buffer.append("b");
buffer.append("c");
buffer.append("d");
buffer.append("e");
String[] expected1 = {"a", "b", "c", "d", "e"};
assertArrayEquals(expected1, buffer.toArray());
String[] expected2 = new String[capacity];
int firstIndex = 0;
int lastIndex = capacity - 1;
expected2[firstIndex] = "e";
for (int i = 1; i < capacity; i++) {
buffer.append("x");
expected2[i] = "x";
}
assertArrayEquals(expected2, buffer.toArray());
buffer.append("x");
expected2[firstIndex] = "x";
assertArrayEquals(expected2, buffer.toArray());
for (int i = 0; i < 10; i++) {
for (String s : expected2) {
buffer.append(s);
}
}
assertArrayEquals(expected2, buffer.toArray());
buffer.append("a");
expected2[lastIndex] = "a";
assertArrayEquals(expected2, buffer.toArray());
}
@Test
public void testGetNextSlot() {
int capacity = 100;
RingBuffer<DummyClass1> buffer = new RingBuffer<>(DummyClass1.class, capacity);
final DummyClass1[] actual = new DummyClass1[capacity];
final DummyClass1[] expected = new DummyClass1[capacity];
for (int i = 0; i < capacity; ++i) {
final DummyClass1 obj = buffer.getNextSlot();
obj.x = capacity * i;
actual[i] = obj;
expected[i] = new DummyClass1();
expected[i].x = capacity * i;
}
assertArrayEquals(expected, buffer.toArray());
for (int i = 0; i < capacity; ++i) {
if (actual[i] != buffer.getNextSlot()) {
fail("getNextSlot() should re-use objects if available");
}
}
RingBuffer<DummyClass2> buffer2 = new RingBuffer<>(DummyClass2.class, capacity);
assertNull("getNextSlot() should return null if the object can't be initiated "
+ "(No nullary constructor)", buffer2.getNextSlot());
RingBuffer<DummyClass3> buffer3 = new RingBuffer<>(DummyClass3.class, capacity);
assertNull("getNextSlot() should return null if the object can't be initiated "
+ "(Inaccessible class)", buffer3.getNextSlot());
}
public static final class DummyClass1 {
int x;
public boolean equals(Object o) {
if (o instanceof DummyClass1) {
final DummyClass1 other = (DummyClass1) o;
return other.x == this.x;
}
return false;
}
}
public static final class DummyClass2 {
public DummyClass2(int x) {}
}
private static final class DummyClass3 {}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,358 @@
/*
* Copyright (C) 2017 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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.IpSecService.IResource;
import com.android.server.IpSecService.RefcountedResource;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
/** Unit tests for {@link IpSecService.RefcountedResource}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class IpSecServiceRefcountedResourceTest {
Context mMockContext;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService;
@Before
public void setUp() throws Exception {
mMockContext = mock(Context.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
}
private void assertResourceState(
RefcountedResource<IResource> resource,
int refCount,
int userReleaseCallCount,
int releaseReferenceCallCount,
int invalidateCallCount,
int freeUnderlyingResourcesCallCount)
throws RemoteException {
// Check refcount on RefcountedResource
assertEquals(refCount, resource.mRefCount);
// Check call count of RefcountedResource
verify(resource, times(userReleaseCallCount)).userRelease();
verify(resource, times(releaseReferenceCallCount)).releaseReference();
// Check call count of IResource
verify(resource.getResource(), times(invalidateCallCount)).invalidate();
verify(resource.getResource(), times(freeUnderlyingResourcesCallCount))
.freeUnderlyingResources();
}
/** Adds mockito instrumentation */
private RefcountedResource<IResource> getTestRefcountedResource(
RefcountedResource... children) {
return getTestRefcountedResource(new Binder(), children);
}
/** Adds mockito instrumentation with provided binder */
private RefcountedResource<IResource> getTestRefcountedResource(
IBinder binder, RefcountedResource... children) {
return spy(
mIpSecService
.new RefcountedResource<IResource>(mock(IResource.class), binder, children));
}
@Test
public void testConstructor() throws RemoteException {
IBinder binderMock = mock(IBinder.class);
RefcountedResource<IResource> resource = getTestRefcountedResource(binderMock);
// Verify resource's refcount starts at 1 (for user-reference)
assertResourceState(resource, 1, 0, 0, 0, 0);
// Verify linking to binder death
verify(binderMock).linkToDeath(anyObject(), anyInt());
}
@Test
public void testConstructorWithChildren() throws RemoteException {
IBinder binderMockChild = mock(IBinder.class);
IBinder binderMockParent = mock(IBinder.class);
RefcountedResource<IResource> childResource = getTestRefcountedResource(binderMockChild);
RefcountedResource<IResource> parentResource =
getTestRefcountedResource(binderMockParent, childResource);
// Verify parent's refcount starts at 1 (for user-reference)
assertResourceState(parentResource, 1, 0, 0, 0, 0);
// Verify child's refcounts were incremented
assertResourceState(childResource, 2, 0, 0, 0, 0);
// Verify linking to binder death
verify(binderMockChild).linkToDeath(anyObject(), anyInt());
verify(binderMockParent).linkToDeath(anyObject(), anyInt());
}
@Test
public void testFailLinkToDeath() throws RemoteException {
IBinder binderMock = mock(IBinder.class);
doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt());
try {
getTestRefcountedResource(binderMock);
fail("Expected exception to propogate when binder fails to link to death");
} catch (RuntimeException expected) {
}
}
@Test
public void testCleanupAndRelease() throws RemoteException {
IBinder binderMock = mock(IBinder.class);
RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
// Verify user-initiated cleanup path decrements refcount and calls full cleanup flow
refcountedResource.userRelease();
assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
// Verify user-initated cleanup path unlinks from binder
verify(binderMock).unlinkToDeath(eq(refcountedResource), eq(0));
assertNull(refcountedResource.mBinder);
}
@Test
public void testMultipleCallsToCleanupAndRelease() throws RemoteException {
RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
// Verify calling userRelease multiple times does not trigger any other cleanup
// methods
refcountedResource.userRelease();
assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
refcountedResource.userRelease();
refcountedResource.userRelease();
assertResourceState(refcountedResource, -1, 3, 1, 1, 1);
}
@Test
public void testBinderDeathAfterCleanupAndReleaseDoesNothing() throws RemoteException {
RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
refcountedResource.userRelease();
assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
// Verify binder death call does not trigger any other cleanup methods if called after
// userRelease()
refcountedResource.binderDied();
assertResourceState(refcountedResource, -1, 2, 1, 1, 1);
}
@Test
public void testBinderDeath() throws RemoteException {
RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
// Verify binder death caused cleanup
refcountedResource.binderDied();
verify(refcountedResource, times(1)).binderDied();
assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
assertNull(refcountedResource.mBinder);
}
@Test
public void testCleanupParentDecrementsChildRefcount() throws RemoteException {
RefcountedResource<IResource> childResource = getTestRefcountedResource();
RefcountedResource<IResource> parentResource = getTestRefcountedResource(childResource);
parentResource.userRelease();
// Verify parent gets cleaned up properly, and triggers releaseReference on
// child
assertResourceState(childResource, 1, 0, 1, 0, 0);
assertResourceState(parentResource, -1, 1, 1, 1, 1);
}
@Test
public void testCleanupReferencedChildDoesNotTriggerRelease() throws RemoteException {
RefcountedResource<IResource> childResource = getTestRefcountedResource();
RefcountedResource<IResource> parentResource = getTestRefcountedResource(childResource);
childResource.userRelease();
// Verify that child does not clean up kernel resources and quota.
assertResourceState(childResource, 1, 1, 1, 1, 0);
assertResourceState(parentResource, 1, 0, 0, 0, 0);
}
@Test
public void testTwoParents() throws RemoteException {
RefcountedResource<IResource> childResource = getTestRefcountedResource();
RefcountedResource<IResource> parentResource1 = getTestRefcountedResource(childResource);
RefcountedResource<IResource> parentResource2 = getTestRefcountedResource(childResource);
// Verify that child does not cleanup kernel resources and quota until all references
// have been released. Assumption: parents release correctly based on
// testCleanupParentDecrementsChildRefcount()
childResource.userRelease();
assertResourceState(childResource, 2, 1, 1, 1, 0);
parentResource1.userRelease();
assertResourceState(childResource, 1, 1, 2, 1, 0);
parentResource2.userRelease();
assertResourceState(childResource, -1, 1, 3, 1, 1);
}
@Test
public void testTwoChildren() throws RemoteException {
RefcountedResource<IResource> childResource1 = getTestRefcountedResource();
RefcountedResource<IResource> childResource2 = getTestRefcountedResource();
RefcountedResource<IResource> parentResource =
getTestRefcountedResource(childResource1, childResource2);
childResource1.userRelease();
assertResourceState(childResource1, 1, 1, 1, 1, 0);
assertResourceState(childResource2, 2, 0, 0, 0, 0);
parentResource.userRelease();
assertResourceState(childResource1, -1, 1, 2, 1, 1);
assertResourceState(childResource2, 1, 0, 1, 0, 0);
childResource2.userRelease();
assertResourceState(childResource1, -1, 1, 2, 1, 1);
assertResourceState(childResource2, -1, 1, 2, 1, 1);
}
@Test
public void testSampleUdpEncapTranform() throws RemoteException {
RefcountedResource<IResource> spi1 = getTestRefcountedResource();
RefcountedResource<IResource> spi2 = getTestRefcountedResource();
RefcountedResource<IResource> udpEncapSocket = getTestRefcountedResource();
RefcountedResource<IResource> transform =
getTestRefcountedResource(spi1, spi2, udpEncapSocket);
// Pretend one SPI goes out of reference (releaseManagedResource -> userRelease)
spi1.userRelease();
// User called releaseManagedResource on udpEncap socket
udpEncapSocket.userRelease();
// User dies, and binder kills the rest
spi2.binderDied();
transform.binderDied();
// Check resource states
assertResourceState(spi1, -1, 1, 2, 1, 1);
assertResourceState(spi2, -1, 1, 2, 1, 1);
assertResourceState(udpEncapSocket, -1, 1, 2, 1, 1);
assertResourceState(transform, -1, 1, 1, 1, 1);
}
@Test
public void testSampleDualTransformEncapSocket() throws RemoteException {
RefcountedResource<IResource> spi1 = getTestRefcountedResource();
RefcountedResource<IResource> spi2 = getTestRefcountedResource();
RefcountedResource<IResource> spi3 = getTestRefcountedResource();
RefcountedResource<IResource> spi4 = getTestRefcountedResource();
RefcountedResource<IResource> udpEncapSocket = getTestRefcountedResource();
RefcountedResource<IResource> transform1 =
getTestRefcountedResource(spi1, spi2, udpEncapSocket);
RefcountedResource<IResource> transform2 =
getTestRefcountedResource(spi3, spi4, udpEncapSocket);
// Pretend one SPIs goes out of reference (releaseManagedResource -> userRelease)
spi1.userRelease();
// User called releaseManagedResource on udpEncap socket and spi4
udpEncapSocket.userRelease();
spi4.userRelease();
// User dies, and binder kills the rest
spi2.binderDied();
spi3.binderDied();
transform2.binderDied();
transform1.binderDied();
// Check resource states
assertResourceState(spi1, -1, 1, 2, 1, 1);
assertResourceState(spi2, -1, 1, 2, 1, 1);
assertResourceState(spi3, -1, 1, 2, 1, 1);
assertResourceState(spi4, -1, 1, 2, 1, 1);
assertResourceState(udpEncapSocket, -1, 1, 3, 1, 1);
assertResourceState(transform1, -1, 1, 1, 1, 1);
assertResourceState(transform2, -1, 1, 1, 1, 1);
}
@Test
public void fuzzTest() throws RemoteException {
List<RefcountedResource<IResource>> resources = new ArrayList<>();
// Build a tree of resources
for (int i = 0; i < 100; i++) {
// Choose a random number of children from the existing list
int numChildren = ThreadLocalRandom.current().nextInt(0, resources.size() + 1);
// Build a (random) list of children
Set<RefcountedResource<IResource>> children = new HashSet<>();
for (int j = 0; j < numChildren; j++) {
int childIndex = ThreadLocalRandom.current().nextInt(0, resources.size());
children.add(resources.get(childIndex));
}
RefcountedResource<IResource> newRefcountedResource =
getTestRefcountedResource(
children.toArray(new RefcountedResource[children.size()]));
resources.add(newRefcountedResource);
}
// Cleanup all resources in a random order
List<RefcountedResource<IResource>> clonedResources =
new ArrayList<>(resources); // shallow copy
while (!clonedResources.isEmpty()) {
int index = ThreadLocalRandom.current().nextInt(0, clonedResources.size());
RefcountedResource<IResource> refcountedResource = clonedResources.get(index);
refcountedResource.userRelease();
clonedResources.remove(index);
}
// Verify all resources were cleaned up properly
for (RefcountedResource<IResource> refcountedResource : resources) {
assertEquals(-1, refcountedResource.mRefCount);
}
}
}

View File

@@ -0,0 +1,670 @@
/*
* Copyright (C) 2017 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;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.EADDRINUSE;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_DGRAM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.IpSecAlgorithm;
import android.net.IpSecConfig;
import android.net.IpSecManager;
import android.net.IpSecSpiResponse;
import android.net.IpSecUdpEncapResponse;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
import android.util.Range;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import dalvik.system.SocketTagger;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import java.io.FileDescriptor;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
/** Unit tests for {@link IpSecService}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class IpSecServiceTest {
private static final int DROID_SPI = 0xD1201D;
private static final int MAX_NUM_ENCAP_SOCKETS = 100;
private static final int MAX_NUM_SPIS = 100;
private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
private static final InetAddress INADDR_ANY;
private static final byte[] AEAD_KEY = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x73, 0x61, 0x6C, 0x74
};
private static final byte[] CRYPT_KEY = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
};
private static final byte[] AUTH_KEY = {
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
};
private static final IpSecAlgorithm AUTH_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
private static final IpSecAlgorithm CRYPT_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
private static final IpSecAlgorithm AEAD_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
static {
try {
INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
Context mMockContext;
INetd mMockNetd;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService;
@Before
public void setUp() throws Exception {
mMockContext = mock(Context.class);
mMockNetd = mock(INetd.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
// Injecting mock netd
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
}
@Test
public void testIpSecServiceCreate() throws InterruptedException {
IpSecService ipSecSrv = IpSecService.create(mMockContext);
assertNotNull(ipSecSrv);
}
@Test
public void testReleaseInvalidSecurityParameterIndex() throws Exception {
try {
mIpSecService.releaseSecurityParameterIndex(1);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
}
/** This function finds an available port */
int findUnusedPort() throws Exception {
// Get an available port.
ServerSocket s = new ServerSocket(0);
int port = s.getLocalPort();
s.close();
return port;
}
@Test
public void testOpenAndCloseUdpEncapsulationSocket() throws Exception {
int localport = -1;
IpSecUdpEncapResponse udpEncapResp = null;
for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) {
localport = findUnusedPort();
udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
assertNotNull(udpEncapResp);
if (udpEncapResp.status == IpSecManager.Status.OK) {
break;
}
// Else retry to reduce possibility for port-bind failures.
}
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
assertEquals(localport, udpEncapResp.port);
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
// Verify quota and RefcountedResource objects cleaned up
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
try {
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
fail("Expected IllegalArgumentException on attempt to access deleted resource");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testUdpEncapsulationSocketBinderDeath() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
IpSecService.RefcountedResource refcountedRecord =
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
udpEncapResp.resourceId);
refcountedRecord.binderDied();
// Verify quota and RefcountedResource objects cleaned up
assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
try {
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
fail("Expected IllegalArgumentException on attempt to access deleted resource");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testOpenUdpEncapsulationSocketAfterClose() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
int localport = udpEncapResp.port;
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
/** Check if localport is available. */
FileDescriptor newSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Os.bind(newSocket, INADDR_ANY, localport);
Os.close(newSocket);
}
/**
* This function checks if the IpSecService holds the reserved port. If
* closeUdpEncapsulationSocket is not called, the socket cleanup should not be complete.
*/
@Test
public void testUdpEncapPortNotReleased() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
int localport = udpEncapResp.port;
udpEncapResp.fileDescriptor.close();
FileDescriptor newSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
try {
Os.bind(newSocket, INADDR_ANY, localport);
fail("ErrnoException not thrown");
} catch (ErrnoException e) {
assertEquals(EADDRINUSE, e.errno);
}
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
}
@Test
public void testOpenUdpEncapsulationSocketOnRandomPort() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
assertNotEquals(0, udpEncapResp.port);
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
}
@Test
public void testOpenUdpEncapsulationSocketPortRange() throws Exception {
try {
mIpSecService.openUdpEncapsulationSocket(TEST_UDP_ENCAP_INVALID_PORT, new Binder());
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
try {
mIpSecService.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT_OUT_RANGE, new Binder());
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
}
@Test
public void testOpenUdpEncapsulationSocketTwice() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
int localport = udpEncapResp.port;
IpSecUdpEncapResponse testUdpEncapResp =
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, testUdpEncapResp.status);
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
}
@Test
public void testCloseInvalidUdpEncapsulationSocket() throws Exception {
try {
mIpSecService.closeUdpEncapsulationSocket(1);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
}
@Test
public void testValidateAlgorithmsAuth() {
// Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig();
config.setAuthentication(AUTH_ALGO);
mIpSecService.validateAlgorithms(config);
// Validate that incorrect algorithm types fails
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {CRYPT_ALGO, AEAD_ALGO}) {
try {
config = new IpSecConfig();
config.setAuthentication(algo);
mIpSecService.validateAlgorithms(config);
fail("Did not throw exception on invalid algorithm type");
} catch (IllegalArgumentException expected) {
}
}
}
@Test
public void testValidateAlgorithmsCrypt() {
// Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig();
config.setEncryption(CRYPT_ALGO);
mIpSecService.validateAlgorithms(config);
// Validate that incorrect algorithm types fails
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, AEAD_ALGO}) {
try {
config = new IpSecConfig();
config.setEncryption(algo);
mIpSecService.validateAlgorithms(config);
fail("Did not throw exception on invalid algorithm type");
} catch (IllegalArgumentException expected) {
}
}
}
@Test
public void testValidateAlgorithmsAead() {
// Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(AEAD_ALGO);
mIpSecService.validateAlgorithms(config);
// Validate that incorrect algorithm types fails
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, CRYPT_ALGO}) {
try {
config = new IpSecConfig();
config.setAuthenticatedEncryption(algo);
mIpSecService.validateAlgorithms(config);
fail("Did not throw exception on invalid algorithm type");
} catch (IllegalArgumentException expected) {
}
}
}
@Test
public void testValidateAlgorithmsAuthCrypt() {
// Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig();
config.setAuthentication(AUTH_ALGO);
config.setEncryption(CRYPT_ALGO);
mIpSecService.validateAlgorithms(config);
}
@Test
public void testValidateAlgorithmsNoAlgorithms() {
IpSecConfig config = new IpSecConfig();
try {
mIpSecService.validateAlgorithms(config);
fail("Expected exception; no algorithms specified");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testValidateAlgorithmsAeadWithAuth() {
IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(AEAD_ALGO);
config.setAuthentication(AUTH_ALGO);
try {
mIpSecService.validateAlgorithms(config);
fail("Expected exception; both AEAD and auth algorithm specified");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testValidateAlgorithmsAeadWithCrypt() {
IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(AEAD_ALGO);
config.setEncryption(CRYPT_ALGO);
try {
mIpSecService.validateAlgorithms(config);
fail("Expected exception; both AEAD and crypt algorithm specified");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testValidateAlgorithmsAeadWithAuthAndCrypt() {
IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(AEAD_ALGO);
config.setAuthentication(AUTH_ALGO);
config.setEncryption(CRYPT_ALGO);
try {
mIpSecService.validateAlgorithms(config);
fail("Expected exception; AEAD, auth and crypt algorithm specified");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testDeleteInvalidTransform() throws Exception {
try {
mIpSecService.deleteTransform(1);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
}
@Test
public void testRemoveTransportModeTransform() throws Exception {
Socket socket = new Socket();
socket.bind(null);
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
mIpSecService.removeTransportModeTransforms(pfd);
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
}
@Test
public void testValidateIpAddresses() throws Exception {
String[] invalidAddresses =
new String[] {"www.google.com", "::", "2001::/64", "0.0.0.0", ""};
for (String address : invalidAddresses) {
try {
IpSecSpiResponse spiResp =
mIpSecService.allocateSecurityParameterIndex(
address, DROID_SPI, new Binder());
fail("Invalid address was passed through IpSecService validation: " + address);
} catch (IllegalArgumentException e) {
} catch (Exception e) {
fail(
"Invalid InetAddress was not caught in validation: "
+ address
+ ", Exception: "
+ e);
}
}
}
/**
* This function checks if the number of encap UDP socket that one UID can reserve has a
* reasonable limit.
*/
@Test
public void testSocketResourceTrackerLimitation() throws Exception {
List<IpSecUdpEncapResponse> openUdpEncapSockets = new ArrayList<IpSecUdpEncapResponse>();
// Reserve sockets until it fails.
for (int i = 0; i < MAX_NUM_ENCAP_SOCKETS; i++) {
IpSecUdpEncapResponse newUdpEncapSocket =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(newUdpEncapSocket);
if (IpSecManager.Status.OK != newUdpEncapSocket.status) {
break;
}
openUdpEncapSockets.add(newUdpEncapSocket);
}
// Assert that the total sockets quota has a reasonable limit.
assertTrue("No UDP encap socket was open", !openUdpEncapSockets.isEmpty());
assertTrue(
"Number of open UDP encap sockets is out of bound",
openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
// Try to reserve one more UDP encapsulation socket, and should fail.
IpSecUdpEncapResponse extraUdpEncapSocket =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(extraUdpEncapSocket);
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraUdpEncapSocket.status);
// Close one of the open UDP encapsulation sockets.
mIpSecService.closeUdpEncapsulationSocket(openUdpEncapSockets.get(0).resourceId);
openUdpEncapSockets.get(0).fileDescriptor.close();
openUdpEncapSockets.remove(0);
// Try to reserve one more UDP encapsulation socket, and should be successful.
extraUdpEncapSocket = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(extraUdpEncapSocket);
assertEquals(IpSecManager.Status.OK, extraUdpEncapSocket.status);
openUdpEncapSockets.add(extraUdpEncapSocket);
// Close open UDP sockets.
for (IpSecUdpEncapResponse openSocket : openUdpEncapSockets) {
mIpSecService.closeUdpEncapsulationSocket(openSocket.resourceId);
openSocket.fileDescriptor.close();
}
}
/**
* This function checks if the number of SPI that one UID can reserve has a reasonable limit.
* This test does not test for both address families or duplicate SPIs because resource tracking
* code does not depend on them.
*/
@Test
public void testSpiResourceTrackerLimitation() throws Exception {
List<IpSecSpiResponse> reservedSpis = new ArrayList<IpSecSpiResponse>();
// Return the same SPI for all SPI allocation since IpSecService only
// tracks the resource ID.
when(mMockNetd.ipSecAllocateSpi(
anyInt(),
anyString(),
eq(InetAddress.getLoopbackAddress().getHostAddress()),
anyInt()))
.thenReturn(DROID_SPI);
// Reserve spis until it fails.
for (int i = 0; i < MAX_NUM_SPIS; i++) {
IpSecSpiResponse newSpi =
mIpSecService.allocateSecurityParameterIndex(
InetAddress.getLoopbackAddress().getHostAddress(),
DROID_SPI + i,
new Binder());
assertNotNull(newSpi);
if (IpSecManager.Status.OK != newSpi.status) {
break;
}
reservedSpis.add(newSpi);
}
// Assert that the SPI quota has a reasonable limit.
assertTrue(reservedSpis.size() > 0 && reservedSpis.size() < MAX_NUM_SPIS);
// Try to reserve one more SPI, and should fail.
IpSecSpiResponse extraSpi =
mIpSecService.allocateSecurityParameterIndex(
InetAddress.getLoopbackAddress().getHostAddress(),
DROID_SPI + MAX_NUM_SPIS,
new Binder());
assertNotNull(extraSpi);
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraSpi.status);
// Release one reserved spi.
mIpSecService.releaseSecurityParameterIndex(reservedSpis.get(0).resourceId);
reservedSpis.remove(0);
// Should successfully reserve one more spi.
extraSpi =
mIpSecService.allocateSecurityParameterIndex(
InetAddress.getLoopbackAddress().getHostAddress(),
DROID_SPI + MAX_NUM_SPIS,
new Binder());
assertNotNull(extraSpi);
assertEquals(IpSecManager.Status.OK, extraSpi.status);
// Release reserved SPIs.
for (IpSecSpiResponse spiResp : reservedSpis) {
mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
}
}
@Test
public void testUidFdtagger() throws Exception {
SocketTagger actualSocketTagger = SocketTagger.get();
try {
FileDescriptor sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Has to be done after socket creation because BlockGuardOS calls tag on new sockets
SocketTagger mockSocketTagger = mock(SocketTagger.class);
SocketTagger.set(mockSocketTagger);
mIpSecService.mUidFdTagger.tag(sockFd, Process.LAST_APPLICATION_UID);
verify(mockSocketTagger).tag(eq(sockFd));
} finally {
SocketTagger.set(actualSocketTagger);
}
}
/**
* Checks if two file descriptors point to the same file.
*
* <p>According to stat.h documentation, the correct way to check for equivalent or duplicated
* file descriptors is to check their inode and device. These two entries uniquely identify any
* file.
*/
private boolean fileDescriptorsEqual(FileDescriptor fd1, FileDescriptor fd2) {
try {
StructStat fd1Stat = Os.fstat(fd1);
StructStat fd2Stat = Os.fstat(fd2);
return fd1Stat.st_ino == fd2Stat.st_ino && fd1Stat.st_dev == fd2Stat.st_dev;
} catch (ErrnoException e) {
return false;
}
}
@Test
public void testOpenUdpEncapSocketTagsSocket() throws Exception {
IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class);
IpSecService testIpSecService = new IpSecService(
mMockContext, mMockIpSecSrvConfig, mockTagger);
IpSecUdpEncapResponse udpEncapResp =
testIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
ArgumentMatcher<FileDescriptor> fdMatcher =
(argFd) -> {
return fileDescriptorsEqual(sockFd, argFd);
};
verify(mockTagger).tag(argThat(fdMatcher), eq(Os.getuid()));
testIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
}
@Test
public void testOpenUdpEncapsulationSocketCallsSetEncapSocketOwner() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
ArgumentMatcher<ParcelFileDescriptor> fdMatcher = (arg) -> {
try {
StructStat sockStat = Os.fstat(sockFd);
StructStat argStat = Os.fstat(arg.getFileDescriptor());
return sockStat.st_ino == argStat.st_ino
&& sockStat.st_dev == argStat.st_dev;
} catch (ErrnoException e) {
return false;
}
};
verify(mMockNetd).ipSecSetEncapSocketOwner(argThat(fdMatcher), eq(Os.getuid()));
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
}
@Test
public void testReserveNetId() {
final Range<Integer> netIdRange = ConnectivityManager.getIpSecNetIdRange();
for (int netId = netIdRange.getLower(); netId <= netIdRange.getUpper(); netId++) {
assertEquals(netId, mIpSecService.reserveNetId());
}
// Check that resource exhaustion triggers an exception
try {
mIpSecService.reserveNetId();
fail("Did not throw error for all netIds reserved");
} catch (IllegalStateException expected) {
}
// Now release one and try again
int releasedNetId =
netIdRange.getLower() + (netIdRange.getUpper() - netIdRange.getLower()) / 2;
mIpSecService.releaseNetId(releasedNetId);
assertEquals(releasedNetId, mIpSecService.reserveNetId());
}
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright (C) 2019 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.
*/
// Don't warn about deprecated types anywhere in this test, because LegacyTypeTracker's very reason
// for existence is to power deprecated APIs. The annotation has to apply to the whole file because
// otherwise warnings will be generated by the imports of deprecated constants like TYPE_xxx.
@file:Suppress("DEPRECATION")
package com.android.server
import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.PackageManager.FEATURE_WIFI
import android.content.pm.PackageManager.FEATURE_WIFI_DIRECT
import android.net.ConnectivityManager.TYPE_ETHERNET
import android.net.ConnectivityManager.TYPE_MOBILE
import android.net.ConnectivityManager.TYPE_MOBILE_CBS
import android.net.ConnectivityManager.TYPE_MOBILE_DUN
import android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY
import android.net.ConnectivityManager.TYPE_MOBILE_FOTA
import android.net.ConnectivityManager.TYPE_MOBILE_HIPRI
import android.net.ConnectivityManager.TYPE_MOBILE_IA
import android.net.ConnectivityManager.TYPE_MOBILE_IMS
import android.net.ConnectivityManager.TYPE_MOBILE_MMS
import android.net.ConnectivityManager.TYPE_MOBILE_SUPL
import android.net.ConnectivityManager.TYPE_VPN
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.ConnectivityManager.TYPE_WIFI_P2P
import android.net.ConnectivityManager.TYPE_WIMAX
import android.net.EthernetManager
import android.net.NetworkInfo.DetailedState.CONNECTED
import android.net.NetworkInfo.DetailedState.DISCONNECTED
import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.server.ConnectivityService.LegacyTypeTracker
import com.android.server.connectivity.NetworkAgentInfo
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertSame
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
const val UNSUPPORTED_TYPE = TYPE_WIMAX
@RunWith(AndroidJUnit4::class)
@SmallTest
class LegacyTypeTrackerTest {
private val supportedTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_MOBILE,
TYPE_MOBILE_SUPL, TYPE_MOBILE_MMS, TYPE_MOBILE_SUPL, TYPE_MOBILE_DUN, TYPE_MOBILE_HIPRI,
TYPE_MOBILE_FOTA, TYPE_MOBILE_IMS, TYPE_MOBILE_CBS, TYPE_MOBILE_IA,
TYPE_MOBILE_EMERGENCY, TYPE_VPN)
private val mMockService = mock(ConnectivityService::class.java).apply {
doReturn(false).`when`(this).isDefaultNetwork(any())
}
private val mPm = mock(PackageManager::class.java)
private val mContext = mock(Context::class.java).apply {
doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI)
doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
doReturn(mPm).`when`(this).packageManager
doReturn(mock(EthernetManager::class.java)).`when`(this).getSystemService(
Context.ETHERNET_SERVICE)
}
private val mTm = mock(TelephonyManager::class.java).apply {
doReturn(true).`when`(this).isDataCapable
}
private fun makeTracker() = LegacyTypeTracker(mMockService).apply {
loadSupportedTypes(mContext, mTm)
}
@Test
fun testSupportedTypes() {
val tracker = makeTracker()
supportedTypes.forEach {
assertTrue(tracker.isTypeSupported(it))
}
assertFalse(tracker.isTypeSupported(UNSUPPORTED_TYPE))
}
@Test
fun testSupportedTypes_NoEthernet() {
doReturn(null).`when`(mContext).getSystemService(Context.ETHERNET_SERVICE)
assertFalse(makeTracker().isTypeSupported(TYPE_ETHERNET))
}
@Test
fun testSupportedTypes_NoTelephony() {
doReturn(false).`when`(mTm).isDataCapable
val tracker = makeTracker()
val nonMobileTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_VPN)
nonMobileTypes.forEach {
assertTrue(tracker.isTypeSupported(it))
}
supportedTypes.toSet().minus(nonMobileTypes).forEach {
assertFalse(tracker.isTypeSupported(it))
}
}
@Test
fun testSupportedTypes_NoWifiDirect() {
doReturn(false).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
val tracker = makeTracker()
assertFalse(tracker.isTypeSupported(TYPE_WIFI_P2P))
supportedTypes.toSet().minus(TYPE_WIFI_P2P).forEach {
assertTrue(tracker.isTypeSupported(it))
}
}
@Test
fun testSupl() {
val tracker = makeTracker()
val mobileNai = mock(NetworkAgentInfo::class.java)
tracker.add(TYPE_MOBILE, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE)
reset(mMockService)
tracker.add(TYPE_MOBILE_SUPL, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
tracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
tracker.add(TYPE_MOBILE_SUPL, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
tracker.remove(mobileNai, false)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE)
}
@Test
fun testAddNetwork() {
val tracker = makeTracker()
val mobileNai = mock(NetworkAgentInfo::class.java)
val wifiNai = mock(NetworkAgentInfo::class.java)
tracker.add(TYPE_MOBILE, mobileNai)
tracker.add(TYPE_WIFI, wifiNai)
assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure adding a second NAI does not change the results.
val secondMobileNai = mock(NetworkAgentInfo::class.java)
tracker.add(TYPE_MOBILE, secondMobileNai)
assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure removing a network that wasn't added for this type is a no-op.
tracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Remove the top network for mobile and make sure the second one becomes the network
// of record for this type.
tracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
assertSame(tracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure adding a network for an unsupported type does not register it.
tracker.add(UNSUPPORTED_TYPE, mobileNai)
assertNull(tracker.getNetworkForType(UNSUPPORTED_TYPE))
}
@Test
fun testBroadcastOnDisconnect() {
val tracker = makeTracker()
val mobileNai1 = mock(NetworkAgentInfo::class.java)
val mobileNai2 = mock(NetworkAgentInfo::class.java)
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
tracker.add(TYPE_MOBILE, mobileNai1)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
reset(mMockService)
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
tracker.add(TYPE_MOBILE, mobileNai2)
verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt())
tracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, DISCONNECTED, TYPE_MOBILE)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE)
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2019 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
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.server.NetIdManager.MIN_NET_ID
import com.android.testutils.assertThrows
import com.android.testutils.ExceptionUtils.ThrowingRunnable
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@SmallTest
class NetIdManagerTest {
@Test
fun testReserveReleaseNetId() {
val manager = NetIdManager(MIN_NET_ID + 4)
assertEquals(MIN_NET_ID, manager.reserveNetId())
assertEquals(MIN_NET_ID + 1, manager.reserveNetId())
assertEquals(MIN_NET_ID + 2, manager.reserveNetId())
assertEquals(MIN_NET_ID + 3, manager.reserveNetId())
manager.releaseNetId(MIN_NET_ID + 1)
manager.releaseNetId(MIN_NET_ID + 3)
// IDs only loop once there is no higher ID available
assertEquals(MIN_NET_ID + 4, manager.reserveNetId())
assertEquals(MIN_NET_ID + 1, manager.reserveNetId())
assertEquals(MIN_NET_ID + 3, manager.reserveNetId())
assertThrows(IllegalStateException::class.java, ThrowingRunnable { manager.reserveNetId() })
manager.releaseNetId(MIN_NET_ID + 5)
// Still no ID available: MIN_NET_ID + 5 was not reserved
assertThrows(IllegalStateException::class.java, ThrowingRunnable { manager.reserveNetId() })
manager.releaseNetId(MIN_NET_ID + 2)
// Throwing an exception still leaves the manager in a working state
assertEquals(MIN_NET_ID + 2, manager.reserveNetId())
}
}

View File

@@ -0,0 +1,315 @@
/*
* Copyright (C) 2012 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;
import static android.util.DebugUtils.valueToString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.annotation.NonNull;
import android.content.Context;
import android.net.INetd;
import android.net.INetdUnsolicitedEventListener;
import android.net.LinkAddress;
import android.net.NetworkPolicyManager;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArrayMap;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.app.IBatteryStats;
import com.android.server.NetworkManagementService.Dependencies;
import com.android.server.net.BaseNetworkObserver;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.function.BiFunction;
/**
* Tests for {@link NetworkManagementService}.
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkManagementServiceTest {
private NetworkManagementService mNMService;
@Mock private Context mContext;
@Mock private IBatteryStats.Stub mBatteryStatsService;
@Mock private INetd.Stub mNetdService;
private static final int TEST_UID = 111;
@NonNull
@Captor
private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
private final MockDependencies mDeps = new MockDependencies();
private final class MockDependencies extends Dependencies {
@Override
public IBinder getService(String name) {
switch (name) {
case BatteryStats.SERVICE_NAME:
return mBatteryStatsService;
default:
throw new UnsupportedOperationException("Unknown service " + name);
}
}
@Override
public void registerLocalService(NetworkManagementInternal nmi) {
}
@Override
public INetd getNetd() {
return mNetdService;
}
@Override
public int getCallingUid() {
return Process.SYSTEM_UID;
}
}
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
doNothing().when(mNetdService)
.registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
// Start the service and wait until it connects to our socket.
mNMService = NetworkManagementService.create(mContext, mDeps);
}
@After
public void tearDown() throws Exception {
mNMService.shutdown();
}
private static <T> T expectSoon(T mock) {
return verify(mock, timeout(200));
}
/**
* Tests that network observers work properly.
*/
@Test
public void testNetworkObservers() throws Exception {
BaseNetworkObserver observer = mock(BaseNetworkObserver.class);
doReturn(new Binder()).when(observer).asBinder(); // Used by registerObserver.
mNMService.registerObserver(observer);
// Forget everything that happened to the mock so far, so we can explicitly verify
// everything that happens and does not happen to it from now on.
INetdUnsolicitedEventListener unsolListener = mUnsolListenerCaptor.getValue();
reset(observer);
// Now call unsolListener methods and ensure that the observer methods are
// called. After every method we expect a callback soon after; to ensure that
// invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
/**
* Interface changes.
*/
unsolListener.onInterfaceAdded("rmnet12");
expectSoon(observer).interfaceAdded("rmnet12");
unsolListener.onInterfaceRemoved("eth1");
expectSoon(observer).interfaceRemoved("eth1");
unsolListener.onInterfaceChanged("clat4", true);
expectSoon(observer).interfaceStatusChanged("clat4", true);
unsolListener.onInterfaceLinkStateChanged("rmnet0", false);
expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
/**
* Bandwidth control events.
*/
unsolListener.onQuotaLimitReached("data", "rmnet_usb0");
expectSoon(observer).limitReached("data", "rmnet_usb0");
/**
* Interface class activity.
*/
unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, TEST_UID);
expectSoon(observer).interfaceClassDataActivityChanged(1, true, 1234, TEST_UID);
unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, TEST_UID);
expectSoon(observer).interfaceClassDataActivityChanged(9, false, 5678, TEST_UID);
unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, TEST_UID);
expectSoon(observer).interfaceClassDataActivityChanged(9, false, 4321, TEST_UID);
/**
* IP address changes.
*/
unsolListener.onInterfaceAddressUpdated("fe80::1/64", "wlan0", 128, 253);
expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253));
unsolListener.onInterfaceAddressRemoved("fe80::1/64", "wlan0", 128, 253);
expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253));
unsolListener.onInterfaceAddressRemoved("2001:db8::1/64", "wlan0", 1, 0);
expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0));
/**
* DNS information broadcasts.
*/
unsolListener.onInterfaceDnsServerInfo("rmnet_usb0", 3600, new String[]{"2001:db8::1"});
expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600,
new String[]{"2001:db8::1"});
unsolListener.onInterfaceDnsServerInfo("wlan0", 14400,
new String[]{"2001:db8::1", "2001:db8::2"});
expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400,
new String[]{"2001:db8::1", "2001:db8::2"});
// We don't check for negative lifetimes, only for parse errors.
unsolListener.onInterfaceDnsServerInfo("wlan0", -3600, new String[]{"::1"});
expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600,
new String[]{"::1"});
// No syntax checking on the addresses.
unsolListener.onInterfaceDnsServerInfo("wlan0", 600,
new String[]{"", "::", "", "foo", "::1"});
expectSoon(observer).interfaceDnsServerInfo("wlan0", 600,
new String[]{"", "::", "", "foo", "::1"});
// Make sure nothing else was called.
verifyNoMoreInteractions(observer);
}
@Test
public void testFirewallEnabled() {
mNMService.setFirewallEnabled(true);
assertTrue(mNMService.isFirewallEnabled());
mNMService.setFirewallEnabled(false);
assertFalse(mNMService.isFirewallEnabled());
}
@Test
public void testNetworkRestrictedDefault() {
assertFalse(mNMService.isNetworkRestricted(TEST_UID));
}
@Test
public void testMeteredNetworkRestrictions() throws RemoteException {
// Make sure the mocked netd method returns true.
doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
// Restrict usage of mobile data in background
mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, true);
assertTrue("Should be true since mobile data usage is restricted",
mNMService.isNetworkRestricted(TEST_UID));
mNMService.setDataSaverModeEnabled(true);
verify(mNetdService).bandwidthEnableDataSaver(true);
mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, false);
assertTrue("Should be true since data saver is on and the uid is not allowlisted",
mNMService.isNetworkRestricted(TEST_UID));
mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, true);
assertFalse("Should be false since data saver is on and the uid is allowlisted",
mNMService.isNetworkRestricted(TEST_UID));
// remove uid from allowlist and turn datasaver off again
mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, false);
mNMService.setDataSaverModeEnabled(false);
verify(mNetdService).bandwidthEnableDataSaver(false);
assertFalse("Network should not be restricted when data saver is off",
mNMService.isNetworkRestricted(TEST_UID));
}
@Test
public void testFirewallChains() {
final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
// Dozable chain
final ArrayMap<Integer, Boolean> isRestrictedForDozable = new ArrayMap<>();
isRestrictedForDozable.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
isRestrictedForDozable.put(INetd.FIREWALL_RULE_ALLOW, false);
isRestrictedForDozable.put(INetd.FIREWALL_RULE_DENY, true);
expected.put(INetd.FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
// Powersaver chain
final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
isRestrictedForPowerSave.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_ALLOW, false);
isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_DENY, true);
expected.put(INetd.FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
// Standby chain
final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
isRestrictedForStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, false);
isRestrictedForStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
isRestrictedForStandby.put(INetd.FIREWALL_RULE_DENY, true);
expected.put(INetd.FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
// Restricted mode chain
final ArrayMap<Integer, Boolean> isRestrictedForRestrictedMode = new ArrayMap<>();
isRestrictedForRestrictedMode.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_ALLOW, false);
isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_DENY, true);
expected.put(INetd.FIREWALL_CHAIN_RESTRICTED, isRestrictedForRestrictedMode);
final int[] chains = {
INetd.FIREWALL_CHAIN_STANDBY,
INetd.FIREWALL_CHAIN_POWERSAVE,
INetd.FIREWALL_CHAIN_DOZABLE,
INetd.FIREWALL_CHAIN_RESTRICTED
};
final int[] states = {
INetd.FIREWALL_RULE_ALLOW,
INetd.FIREWALL_RULE_DENY,
NetworkPolicyManager.FIREWALL_RULE_DEFAULT
};
BiFunction<Integer, Integer, String> errorMsg = (chain, state) -> {
return String.format("Unexpected value for chain: %s and state: %s",
valueToString(INetd.class, "FIREWALL_CHAIN_", chain),
valueToString(INetd.class, "FIREWALL_RULE_", state));
};
for (int chain : chains) {
final ArrayMap<Integer, Boolean> expectedValues = expected.get(chain);
mNMService.setFirewallChainEnabled(chain, true);
for (int state : states) {
mNMService.setFirewallUidRule(chain, TEST_UID, state);
assertEquals(errorMsg.apply(chain, state),
expectedValues.get(state), mNMService.isNetworkRestricted(TEST_UID));
}
mNMService.setFirewallChainEnabled(chain, false);
}
}
}

Some files were not shown because too many files have changed in this diff Show More