Snap for 4818534 from 1e53f6b418d977186f945cd9d646f18f770db346 to pi-release

Change-Id: I8a39d0b29bd6f3055d316be12f3a6033372f30a8
diff --git a/Android.mk b/Android.mk
index 99559ac..952fa9d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -28,3 +28,5 @@
 LOCAL_MODULE := ethernet-service
 
 include $(BUILD_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/java/com/android/server/ethernet/EthernetTracker.java b/java/com/android/server/ethernet/EthernetTracker.java
index 688d84a..00eedd5 100644
--- a/java/com/android/server/ethernet/EthernetTracker.java
+++ b/java/com/android/server/ethernet/EthernetTracker.java
@@ -36,10 +36,13 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.net.BaseNetworkObserver;
 
 import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -300,7 +303,7 @@
         mNetworkCapabilities.put(name, nc);
 
         if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) {
-            IpConfiguration ipConfig = createStaticIpConfiguration(tokens[2]);
+            IpConfiguration ipConfig = parseStaticIpConfiguration(tokens[2]);
             mIpConfigurations.put(name, ipConfig);
         }
     }
@@ -342,11 +345,54 @@
         return nc;
     }
 
-    private static IpConfiguration createStaticIpConfiguration(String strIpAddress) {
-        StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
-        staticIpConfiguration.ipAddress = new LinkAddress(strIpAddress);
-        return new IpConfiguration(
-                IpAssignment.STATIC, ProxySettings.NONE, staticIpConfiguration, null);
+    /**
+     * Parses static IP configuration.
+     *
+     * @param staticIpConfig represents static IP configuration in the following format: {@code
+     * ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses>
+     *     domains=<comma-sep-domains>}
+     */
+    @VisibleForTesting
+    static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) {
+        StaticIpConfiguration ipConfig = new StaticIpConfiguration();
+
+        for (String keyValueAsString : staticIpConfig.trim().split(" ")) {
+            if (TextUtils.isEmpty(keyValueAsString)) continue;
+
+            String[] pair = keyValueAsString.split("=");
+            if (pair.length != 2) {
+                throw new IllegalArgumentException("Unexpected token: " + keyValueAsString
+                        + " in " + staticIpConfig);
+            }
+
+            String key = pair[0];
+            String value = pair[1];
+
+            switch (key) {
+                case "ip":
+                    ipConfig.ipAddress = new LinkAddress(value);
+                    break;
+                case "domains":
+                    ipConfig.domains = value;
+                    break;
+                case "gateway":
+                    ipConfig.gateway = InetAddress.parseNumericAddress(value);
+                    break;
+                case "dns": {
+                    ArrayList<InetAddress> dnsAddresses = new ArrayList<>();
+                    for (String address: value.split(",")) {
+                        dnsAddresses.add(InetAddress.parseNumericAddress(address));
+                    }
+                    ipConfig.dnsServers.addAll(dnsAddresses);
+                    break;
+                }
+                default : {
+                    throw new IllegalArgumentException("Unexpected key: " + key
+                            + " in " + staticIpConfig);
+                }
+            }
+        }
+        return new IpConfiguration(IpAssignment.STATIC, ProxySettings.NONE, ipConfig, null);
     }
 
     private static IpConfiguration createDefaultIpConfiguration() {
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 0000000..6b2c103
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1,36 @@
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, java)
+
+LOCAL_PACKAGE_NAME := EthernetServiceTests
+
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := \
+        android.test.runner \
+        android.test.base
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+        android-support-test \
+        ethernet-service
+
+include $(BUILD_PACKAGE)
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
new file mode 100644
index 0000000..1bc0775
--- /dev/null
+++ b/tests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.server.ethernet.tests">
+
+    <application android:label="EthernetServiceTests">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.server.ethernet.tests"
+        android:label="Ethernet Service Tests" />
+</manifest>
diff --git a/tests/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/java/com/android/server/ethernet/EthernetTrackerTest.java
new file mode 100644
index 0000000..70d316d
--- /dev/null
+++ b/tests/java/com/android/server/ethernet/EthernetTrackerTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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 com.android.server.ethernet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.net.IpConfiguration;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.LinkAddress;
+import android.net.StaticIpConfiguration;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EthernetTrackerTest {
+
+    @Test
+    public void createStaticIpConfiguration() {
+        assertStaticConfiguration("", new StaticIpConfiguration());
+
+        assertStaticConfiguration(
+                "ip=192.0.2.10/24",
+                new StaticIpConfigBuilder().setIp("192.0.2.10/24").build());
+
+        assertStaticConfiguration(
+                "ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android",
+                new StaticIpConfigBuilder()
+                        .setIp("192.0.2.10/24")
+                        .setDns(new String[] {"4.4.4.4", "8.8.8.8"})
+                        .setGateway("192.0.2.1")
+                        .setDomains("android")
+                        .build());
+
+        // Verify order doesn't matter
+        assertStaticConfiguration(
+                "domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 ",
+                new StaticIpConfigBuilder()
+                        .setIp("192.0.2.10/24")
+                        .setDns(new String[] {"4.4.4.4", "8.8.8.8"})
+                        .setGateway("192.0.2.1")
+                        .setDomains("android")
+                        .build());
+    }
+
+    @Test
+    public void createStaticIpConfiguration_Bad() {
+        assertFails("ip=192.0.2.1/24 gateway= blah=20.20.20.20");  // Unknown key
+        assertFails("ip=192.0.2.1");  // mask is missing
+        assertFails("ip=a.b.c");  // not a valid ip address
+        assertFails("dns=4.4.4.4,1.2.3.A");  // not valid ip address in dns
+        assertFails("=");  // Key and value is empty
+        assertFails("ip=");  // Value is empty
+        assertFails("ip=192.0.2.1/24 gateway=");  // Gateway is empty
+    }
+
+    private void assertFails(String config) {
+        try {
+            EthernetTracker.parseStaticIpConfiguration(config);
+            fail("Expected to fail: " + config);
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    private void assertStaticConfiguration(String configAsString,
+            StaticIpConfiguration expectedStaticIpConfig) {
+        IpConfiguration expectedIpConfiguration = new IpConfiguration(IpAssignment.STATIC,
+                ProxySettings.NONE, expectedStaticIpConfig, null);
+
+        assertEquals(expectedIpConfiguration,
+                EthernetTracker.parseStaticIpConfiguration(configAsString));
+    }
+
+    private static class StaticIpConfigBuilder {
+        private final StaticIpConfiguration config = new StaticIpConfiguration();
+
+        StaticIpConfigBuilder setIp(String address) {
+            config.ipAddress = new LinkAddress(address);
+            return this;
+        }
+
+        StaticIpConfigBuilder setDns(String[] dnsArray) {
+            for (String dns : dnsArray) {
+                config.dnsServers.add(InetAddress.parseNumericAddress(dns));
+            }
+            return this;
+        }
+
+        StaticIpConfigBuilder setGateway(String gateway) {
+            config.gateway = InetAddress.parseNumericAddress(gateway);
+            return this;
+        }
+
+        StaticIpConfigBuilder setDomains(String domains) {
+            config.domains = domains;
+            return this;
+        }
+
+
+        StaticIpConfiguration build() {
+            return new StaticIpConfiguration(config);
+        }
+    }
+}