Have a collection of utilities for netd - NetdUtils
Some files which will be inside mainline module depend on NetworkManagementService to talk to netd, but after they become a part of mainline module, they cannot access @hide API of NetworkManagementService. So create a NetdUtils to help them to talk to netd. Bug: 170598012 Test: atest CtsNetTestCasesLatestSdk NetdStaticLibTests Change-Id: I8bee1204b9533b70844da0b3768427438fd0c890
This commit is contained in:
parent
37a2effb07
commit
5c620643b7
5 changed files with 278 additions and 1 deletions
|
|
@ -9,7 +9,9 @@ java_library {
|
|||
],
|
||||
visibility: [
|
||||
"//packages/modules/Connectivity/Tethering",
|
||||
"//frameworks/base/services:__subpackages__"
|
||||
"//frameworks/base/services:__subpackages__",
|
||||
"//frameworks/base/packages:__subpackages__",
|
||||
"//frameworks/libs/net/client-libs/tests:__subpackages__",
|
||||
],
|
||||
libs: ["androidx.annotation_annotation"],
|
||||
static_libs: [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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 com.android.net.module.util;
|
||||
|
||||
import static android.net.INetd.IF_STATE_DOWN;
|
||||
import static android.net.INetd.IF_STATE_UP;
|
||||
|
||||
import android.net.INetd;
|
||||
import android.net.InterfaceConfigurationParcel;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceSpecificException;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Collection of utilities for netd.
|
||||
*/
|
||||
public class NetdUtils {
|
||||
/**
|
||||
* Get InterfaceConfigurationParcel from netd.
|
||||
*/
|
||||
public static InterfaceConfigurationParcel getInterfaceConfigParcel(@NonNull INetd netd,
|
||||
@NonNull String iface) {
|
||||
try {
|
||||
return netd.interfaceGetCfg(iface);
|
||||
} catch (RemoteException | ServiceSpecificException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateFlag(String flag) {
|
||||
if (flag.indexOf(' ') >= 0) {
|
||||
throw new IllegalArgumentException("flag contains space: " + flag);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected static String[] removeAndAddFlags(@NonNull String[] flags, @NonNull String remove,
|
||||
@NonNull String add) {
|
||||
final ArrayList<String> result = new ArrayList<>();
|
||||
try {
|
||||
// Validate the add flag first, so that the for-loop can be ignore once the format of
|
||||
// add flag is invalid.
|
||||
validateFlag(add);
|
||||
for (String flag : flags) {
|
||||
// Simply ignore both of remove and add flags first, then add the add flag after
|
||||
// exiting the loop to prevent adding the duplicate flag.
|
||||
if (remove.equals(flag) || add.equals(flag)) continue;
|
||||
result.add(flag);
|
||||
}
|
||||
result.add(add);
|
||||
return result.toArray(new String[result.size()]);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IllegalStateException("Invalid InterfaceConfigurationParcel", iae);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set interface configuration to netd by passing InterfaceConfigurationParcel.
|
||||
*/
|
||||
public static void setInterfaceConfig(INetd netd, InterfaceConfigurationParcel configParcel) {
|
||||
try {
|
||||
netd.interfaceSetCfg(configParcel);
|
||||
} catch (RemoteException | ServiceSpecificException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given interface up.
|
||||
*/
|
||||
public static void setInterfaceUp(INetd netd, String iface) {
|
||||
final InterfaceConfigurationParcel configParcel = getInterfaceConfigParcel(netd, iface);
|
||||
configParcel.flags = removeAndAddFlags(configParcel.flags, IF_STATE_DOWN /* remove */,
|
||||
IF_STATE_UP /* add */);
|
||||
setInterfaceConfig(netd, configParcel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given interface down.
|
||||
*/
|
||||
public static void setInterfaceDown(INetd netd, String iface) {
|
||||
final InterfaceConfigurationParcel configParcel = getInterfaceConfigParcel(netd, iface);
|
||||
configParcel.flags = removeAndAddFlags(configParcel.flags, IF_STATE_UP /* remove */,
|
||||
IF_STATE_DOWN /* add */);
|
||||
setInterfaceConfig(netd, configParcel);
|
||||
}
|
||||
}
|
||||
39
staticlibs/client-libs/tests/unit/Android.bp
Normal file
39
staticlibs/client-libs/tests/unit/Android.bp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
android_library {
|
||||
name: "NetdStaticLibTestsLib",
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
"src/**/*.kt",
|
||||
],
|
||||
min_sdk_version: "29",
|
||||
static_libs: [
|
||||
"androidx.test.rules",
|
||||
"mockito-target-extended-minus-junit4",
|
||||
"net-tests-utils-host-device-common",
|
||||
"netd-client",
|
||||
],
|
||||
libs: [
|
||||
"android.test.runner",
|
||||
"android.test.base",
|
||||
],
|
||||
visibility: [
|
||||
// Visible for Tethering and NetworkStack integration test and link NetdStaticLibTestsLib
|
||||
// there, so that the tests under client-libs can also be run when running tethering and
|
||||
// NetworkStack MTS.
|
||||
"//packages/modules/Connectivity/Tethering/tests/integration",
|
||||
"//packages/modules/NetworkStack/tests/integration",
|
||||
]
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "NetdStaticLibTests",
|
||||
certificate: "platform",
|
||||
static_libs: [
|
||||
"NetdStaticLibTestsLib",
|
||||
],
|
||||
jni_libs: [
|
||||
// For mockito extended
|
||||
"libdexmakerjvmtiagent",
|
||||
"libstaticjvmtiagent",
|
||||
],
|
||||
test_suites: ["device-tests"],
|
||||
}
|
||||
28
staticlibs/client-libs/tests/unit/AndroidManifest.xml
Normal file
28
staticlibs/client-libs/tests/unit/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.frameworks.clientlibs.tests">
|
||||
|
||||
<application android:debuggable="true">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<instrumentation
|
||||
android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.frameworks.clientlibs.tests"
|
||||
android:label="Netd Static Library Tests" />
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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 com.android.net.module.util;
|
||||
|
||||
import static com.android.testutils.MiscAsserts.assertThrows;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.net.INetd;
|
||||
import android.net.InterfaceConfigurationParcel;
|
||||
|
||||
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 java.util.Arrays;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class NetdUtilsTest {
|
||||
@Mock private INetd mNetd;
|
||||
|
||||
private static final String IFACE = "TEST_IFACE";
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
private void setupFlagsForInterfaceConfiguration(String[] flags) throws Exception {
|
||||
final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
|
||||
config.flags = flags;
|
||||
when(mNetd.interfaceGetCfg(eq(IFACE))).thenReturn(config);
|
||||
}
|
||||
|
||||
private void verifyMethodsAndArgumentsOfSetInterface(boolean ifaceUp) throws Exception {
|
||||
final String[] flagsContainDownAndUp = new String[] {"flagA", "down", "flagB", "up"};
|
||||
final String[] flagsForInterfaceDown = new String[] {"flagA", "down", "flagB"};
|
||||
final String[] flagsForInterfaceUp = new String[] {"flagA", "up", "flagB"};
|
||||
final String[] expectedFinalFlags;
|
||||
setupFlagsForInterfaceConfiguration(flagsContainDownAndUp);
|
||||
if (ifaceUp) {
|
||||
// "down" flag will be removed from flagsContainDownAndUp when interface is up. Set
|
||||
// expectedFinalFlags to flagsForInterfaceUp.
|
||||
expectedFinalFlags = flagsForInterfaceUp;
|
||||
NetdUtils.setInterfaceUp(mNetd, IFACE);
|
||||
} else {
|
||||
// "up" flag will be removed from flagsContainDownAndUp when interface is down. Set
|
||||
// expectedFinalFlags to flagsForInterfaceDown.
|
||||
expectedFinalFlags = flagsForInterfaceDown;
|
||||
NetdUtils.setInterfaceDown(mNetd, IFACE);
|
||||
}
|
||||
verify(mNetd).interfaceSetCfg(
|
||||
argThat(config ->
|
||||
// Check if actual flags are the same as expected flags.
|
||||
// TODO: Have a function in MiscAsserts to check if two arrays are the same.
|
||||
CollectionUtils.all(Arrays.asList(expectedFinalFlags),
|
||||
flag -> Arrays.asList(config.flags).contains(flag))
|
||||
&& CollectionUtils.all(Arrays.asList(config.flags),
|
||||
flag -> Arrays.asList(expectedFinalFlags).contains(flag))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetInterfaceUp() throws Exception {
|
||||
verifyMethodsAndArgumentsOfSetInterface(true /* ifaceUp */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetInterfaceDown() throws Exception {
|
||||
verifyMethodsAndArgumentsOfSetInterface(false /* ifaceUp */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveAndAddFlags() throws Exception {
|
||||
final String[] flags = new String[] {"flagA", "down", "flagB"};
|
||||
// Add an invalid flag and expect to get an IllegalStateException.
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> NetdUtils.removeAndAddFlags(flags, "down" /* remove */, "u p" /* add */));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue