From 5adb3c56aa505288bf415f49178f692acbb22de8 Mon Sep 17 00:00:00 2001 From: Chuwei He Date: Thu, 19 Jun 2025 16:31:35 +0900 Subject: [PATCH] Add proto to store network configuration This patch adds proto which will be used to store network configuration. This will be used in IpConfigStore. Test: atest ConnectivityCoverageTests Bug: 397536853 Flag: EXEMPT mainline Change-Id: I83032ebc78c60cbf2fc8f9119471fc13ae7f09e1 --- service-t/Android.bp | 19 +++ service-t/src/proto/configstore.proto | 117 ++++++++++++++++++ .../server/net/NetworkConfigStoreProtoTest.kt | 104 ++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 service-t/src/proto/configstore.proto create mode 100644 tests/unit/java/com/android/server/net/NetworkConfigStoreProtoTest.kt diff --git a/service-t/Android.bp b/service-t/Android.bp index 8d780b705e..1cafc31213 100644 --- a/service-t/Android.bp +++ b/service-t/Android.bp @@ -72,6 +72,7 @@ java_library { // service-connectivity-pre-jarjar), and in the case of code that is already in // framework-connectivity, the classes would be included in the apex twice. "modules-utils-statemachine", + "service-connectivity-tiramisu-protos", ], apex_available: [ "com.android.tethering", @@ -92,6 +93,24 @@ java_library { }, } +java_library { + name: "service-connectivity-tiramisu-protos", + sdk_version: "core_current", + proto: { + type: "lite", + }, + srcs: [ + "src/proto/*.proto", + ], + static_libs: ["libprotobuf-java-lite"], + apex_available: [ + "com.android.tethering", + ], + lint: { + strict_updatability_linting: true, + }, +} + // Test building mDNS as a standalone, so that it can be imported into other repositories as-is. // The mDNS code is platform code so it should use framework-annotations-lib, contrary to apps that // should use sdk_version: "system_current" and only androidx.annotation_annotation. But this build diff --git a/service-t/src/proto/configstore.proto b/service-t/src/proto/configstore.proto new file mode 100644 index 0000000000..ce84ceeb5d --- /dev/null +++ b/service-t/src/proto/configstore.proto @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2025 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. + */ + +// This file contains messages for representing the basic information and +// configuration of an network interface. +// +// Messages defined in this file are stored on disk, so reader should be able +// to parse all historic versions of the serialized data, and to merge data +// with different serialization formats. +syntax = "proto2"; +package com_android_server_network_configstore; + +option java_package = "com.android.server.network.configstore.proto"; +option java_outer_classname = "NetworkConfigStoreProto"; + +// Represents an IPv4 address along with its prefix length. +message LinkAddress { + // The string of the IPv4 address in the format of IPv4 address in dotted decimal notation, for + // example "192.168.1.50". + required string address = 1; + // The prefix length of the IP address, indicating the subnet mask. + required int32 prefix_length = 2; +} + +// Configuration for a static IPv4 assignment. +message StaticIpv4Configuration { + // The IPv4 address and prefix length for the static IPv4 configuration. + required LinkAddress address = 1; + // The gateway IPv4 address as string in the format of IPv4 address in dotted decimal notation, + // for example "192.168.1.100". + optional string gateway = 2; + // A list of DNS server IPv4 addresses as strings in the format of IPv4 address in dotted + // decimal notation, for example "8.8.8.8". + repeated string dns_servers = 3; + // A list of domains to search when resolving host names on this link, in priority order. + repeated string search_domains = 4; +} + +// Manual configuration of the proxy server. +message ManualProxyConfig { + // A list of hosts for which the proxy should not be used. + repeated string exclusion_hosts = 1; + // The hostname or IP address of the proxy server. + required string host = 2; + // The port number of the proxy server. + required int32 port = 3; +} + +// Configuration using a PAC (Proxy Auto-Configuration) script downloaded from a URL. +message PacUrlConfig { + // The URL of the Proxy Auto-Configuration (PAC) file. + required string pac_url = 1; +} + +// IP configuration for the interface. +message IpConfiguration { + // IPv4 configuration of this interface. Making this an oneoff field because of the possibility + // of adding DHCP IPv4 configuration in the future. + oneof ipv4_configuration { + // Static IPv4 configuration of this interface. DHCP is not used when a static configuration + // exists. + StaticIpv4Configuration static_ipv4_config = 1; + } + // Proxy configuration to use for network connections on this interface, when not set, means + // no proxy configuration is used. + oneof proxy_config { + // Manual proxy configuration. + ManualProxyConfig manual_proxy_config = 2; + // PAC (Proxy Auto-Configuration) configuration. + PacUrlConfig pac_url_config = 3; + } +} + +// Defines a selector to identify the ethernet port. +message EthernetPortSelector { + oneof identifier { + // MAC address of this ethernet port. + string mac_addr = 1; + // Interface name of this ethernet port. + string iface_name = 2; + } +} + +// Enum for metered override configuration. +enum MeteredOverride { + // There is no metered override configuration. + METERED_OVERRIDE_NONE = 0; + // Forces the connection to be treated as metered. + METERED_OVERRIDE_FORCE_METERED = 1; + // Forces the connection to be treated as unmetered. + METERED_OVERRIDE_FORCE_UNMETERED = 2; +} + +// Defines the configuration of an ethernet interface. +message EthernetConfiguration { + // Selector for applying this configuration to an Ethernet port, containing identifiable + // information of related ethernet port. + required EthernetPortSelector selector = 1; + // IP configuration of this ethernet interface. + required IpConfiguration ip_config = 2; + // Static metered override configuration, note that this is not the actual meteredness but + // static configuration. + required MeteredOverride metered_override = 3; +} \ No newline at end of file diff --git a/tests/unit/java/com/android/server/net/NetworkConfigStoreProtoTest.kt b/tests/unit/java/com/android/server/net/NetworkConfigStoreProtoTest.kt new file mode 100644 index 0000000000..543ea2f5a6 --- /dev/null +++ b/tests/unit/java/com/android/server/net/NetworkConfigStoreProtoTest.kt @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2025 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 androidx.test.filters.SmallTest +import com.android.server.network.configstore.proto.NetworkConfigStoreProto +import com.android.server.network.configstore.proto.NetworkConfigStoreProto.MeteredOverride +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.mockito.MockitoAnnotations + +/** + * Unit tests for [com.android.server.ethernet.proto.NetworkConfigStoreProto]. + */ +@SmallTest +class NetworkConfigStoreProtoTest { + companion object { + private const val IFACE_NAME = "eth0" + private const val ADDR = "192.0.2.1" + private const val PREFIX_LEN = 25 + private const val GATEWAY = "192.0.2.129" + private const val DNS1 = "8.8.8.8" + private const val DNS2 = "8.8.8.4" + private const val EXCLUSION_LIST1 = "com.example.app" + private const val EXCLUSION_LIST2 = "localhost" + private const val PROXY_HOST = "proxy.example.com" + private const val PROXY_PORT = 8080 + } + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + } + + @Test + fun testBuilder() { + val selector = NetworkConfigStoreProto.EthernetPortSelector.newBuilder().apply { + ifaceName = IFACE_NAME + }.build() + assertEquals(IFACE_NAME, selector.ifaceName) + + val linkAddr = NetworkConfigStoreProto.LinkAddress.newBuilder().apply { + address = ADDR + prefixLength = PREFIX_LEN + }.build() + assertEquals(ADDR, linkAddr.address) + assertEquals(PREFIX_LEN, linkAddr.prefixLength) + + val staticIpv4Configuration = + NetworkConfigStoreProto.StaticIpv4Configuration.newBuilder().apply { + address = linkAddr + gateway = GATEWAY + addDnsServers(DNS1) + addDnsServers(DNS2) + }.build() + assertEquals(linkAddr, staticIpv4Configuration.address) + assertEquals(GATEWAY, staticIpv4Configuration.gateway) + assertEquals(DNS1, staticIpv4Configuration.getDnsServers(0)) + assertEquals(DNS2, staticIpv4Configuration.getDnsServers(1)) + + val manualProxy = NetworkConfigStoreProto.ManualProxyConfig.newBuilder().apply { + host = PROXY_HOST + port = PROXY_PORT + addExclusionHosts(EXCLUSION_LIST1) + addExclusionHosts(EXCLUSION_LIST2) + }.build() + assertEquals(PROXY_HOST, manualProxy.host) + assertEquals(PROXY_PORT, manualProxy.port) + assertEquals(EXCLUSION_LIST1, manualProxy.getExclusionHosts(0)) + assertEquals(EXCLUSION_LIST2, manualProxy.getExclusionHosts(1)) + + val ipConfig = NetworkConfigStoreProto.IpConfiguration.newBuilder().apply { + staticIpv4Config = staticIpv4Configuration + manualProxyConfig = manualProxy + }.build() + assertEquals(staticIpv4Configuration, ipConfig.staticIpv4Config) + assertEquals(manualProxy, ipConfig.manualProxyConfig) + + val ethConfig = NetworkConfigStoreProto.EthernetConfiguration.newBuilder().apply { + setSelector(selector) + setIpConfig(ipConfig) + meteredOverride = MeteredOverride.METERED_OVERRIDE_FORCE_METERED + }.build() + assertEquals(selector, ethConfig.selector) + assertEquals(ipConfig, ethConfig.ipConfig) + assertEquals(MeteredOverride.METERED_OVERRIDE_FORCE_METERED, ethConfig.meteredOverride) + assertEquals(staticIpv4Configuration, ethConfig.ipConfig.staticIpv4Config) + } +}