Merge "Makes wifi configurable over shared memory" into gce-dev
diff --git a/common/frontend/socket_forward_proxy/Android.bp b/common/frontend/socket_forward_proxy/Android.bp
index c70983e..caad62b 100644
--- a/common/frontend/socket_forward_proxy/Android.bp
+++ b/common/frontend/socket_forward_proxy/Android.bp
@@ -21,6 +21,7 @@
     shared_libs: [
         "libbase",
         "libcuttlefish_fs",
+        "libcuttlefish_strings",
         "cuttlefish_auto_resources",
         "vsoc_lib",
         "liblog",
diff --git a/common/frontend/socket_forward_proxy/main.cpp b/common/frontend/socket_forward_proxy/main.cpp
index ad1ca10..ed4196e 100644
--- a/common/frontend/socket_forward_proxy/main.cpp
+++ b/common/frontend/socket_forward_proxy/main.cpp
@@ -29,6 +29,7 @@
 #include <unistd.h>
 
 #include "common/libs/fs/shared_fd.h"
+#include "common/libs/strings/str_split.h"
 #include "common/vsoc/lib/socket_forward_region_view.h"
 
 #ifdef CUTTLEFISH_HOST
@@ -39,9 +40,12 @@
 using vsoc::socket_forward::SocketForwardRegionView;
 
 #ifdef CUTTLEFISH_HOST
-DEFINE_string(ports, "",
-              "Comma-separated list of ports from which to forward TCP "
-              "connections.");
+DEFINE_string(guest_ports, "",
+              "Comma-separated list of ports on which to forward TCP "
+              "connections to the guest.");
+DEFINE_string(host_ports, "",
+              "Comma-separated list of ports on which to run TCP servers on "
+              "the host.");
 #endif
 
 namespace {
@@ -154,44 +158,53 @@
 }
 
 #ifdef CUTTLEFISH_HOST
+struct PortPair {
+  int guest_port;
+  int host_port;
+};
+
+
 [[noreturn]] void host_impl(SocketForwardRegionView* shm,
-                            std::vector<int> ports, std::size_t index) {
+                            std::vector<PortPair> ports, std::size_t index) {
   // launch a worker for the following port before handling the current port.
   // recursion (instead of a loop) removes the need fore any join() or having
   // the main thread do no work.
   if (index + 1 < ports.size()) {
     std::thread(host_impl, shm, ports, index + 1).detach();
   }
-  auto remote_port = ports[index];
-  auto local_port = vsoc::GetPerInstanceDefault(remote_port);
-  LOG(INFO) << "starting server on " << local_port
-            << " for guest port " << remote_port;
-  auto server = cvd::SharedFD::SocketLocalServer(local_port, SOCK_STREAM);
-  CHECK(server->IsOpen()) << "Could not start server on port " << local_port;
+  auto guest_port = ports[index].guest_port;
+  auto host_port = ports[index].host_port;
+  LOG(INFO) << "starting server on " << host_port
+            << " for guest port " << guest_port;
+  auto server = cvd::SharedFD::SocketLocalServer(host_port, SOCK_STREAM);
+  CHECK(server->IsOpen()) << "Could not start server on port " << host_port;
   while (true) {
     auto client_socket = cvd::SharedFD::Accept(*server);
     CHECK(client_socket->IsOpen()) << "error creating client socket";
     LOG(INFO) << "client socket accepted";
-    auto conn = shm->OpenConnection(remote_port);
+    auto conn = shm->OpenConnection(guest_port);
     LOG(INFO) << "shm connection opened";
     LaunchWorkers(std::move(conn), std::move(client_socket));
   }
 }
 
 [[noreturn]] void host(SocketForwardRegionView* shm,
-                           std::vector<int> ports) {
+                       std::vector<PortPair> ports) {
   CHECK(!ports.empty());
   host_impl(shm, ports, 0);
 }
 
-std::vector<int> ParsePortsList(const std::string& ports_flag) {
-  std::istringstream ports_stream{ports_flag};
-  std::vector<int> ports;
-  std::string port_str{};
-  while (std::getline(ports_stream, port_str, ',')) {
-    ports.push_back(std::stoi(port_str));
+std::vector<PortPair> ParsePortsList(const std::string& guest_ports_str,
+                                const std::string& host_ports_str) {
+  std::vector<PortPair> ports{};
+  auto guest_ports = cvd::StrSplit(guest_ports_str, ',');
+  auto host_ports = cvd::StrSplit(host_ports_str, ',');
+  CHECK(guest_ports.size() == host_ports.size());
+  for (std::size_t i = 0; i < guest_ports.size(); ++i) {
+    ports.push_back({std::stoi(guest_ports[i]), std::stoi(host_ports[i])});
   }
   return ports;
+
 }
 
 #else
@@ -250,8 +263,9 @@
   auto worker = shm->StartWorker();
 
 #ifdef CUTTLEFISH_HOST
-  CHECK(!FLAGS_ports.empty()) << "Must specify --ports flag";
-  host(shm, ParsePortsList(FLAGS_ports));
+  CHECK(!FLAGS_guest_ports.empty()) << "Must specify --guest_ports flag";
+  CHECK(!FLAGS_host_ports.empty()) << "Must specify --host_ports flag";
+  host(shm, ParsePortsList(FLAGS_guest_ports, FLAGS_host_ports));
 #else
   guest(shm);
 #endif
diff --git a/common/libs/Android.bp b/common/libs/Android.bp
index b23571f..cb4ec3e 100644
--- a/common/libs/Android.bp
+++ b/common/libs/Android.bp
@@ -17,6 +17,7 @@
     "auto_resources",
     "fs",
     "net",
+    "strings",
     "tcp_socket",
     "threads",
     "time",
diff --git a/common/libs/net/network_interface_manager.cpp b/common/libs/net/network_interface_manager.cpp
index 32d5583..4ee96b7 100644
--- a/common/libs/net/network_interface_manager.cpp
+++ b/common/libs/net/network_interface_manager.cpp
@@ -75,15 +75,22 @@
     : nl_client_(std::move(nl_client)) {}
 
 std::unique_ptr<NetworkInterface> NetworkInterfaceManager::Open(
-    const std::string& if_name) {
+    const std::string& if_name, const std::string& if_name_alt) {
   std::unique_ptr<NetworkInterface> iface;
   // NOTE: do not replace this code with an IOCTL call.
   // On SELinux enabled Androids, RILD is not permitted to execute an IOCTL
   // and this call will fail.
-  const int32_t index = if_nametoindex(if_name.c_str());
-  if (index < 0) {
-    LOG(ERROR) << "Failed to get interface (" << if_name << ") index.";
-    return iface;
+  int32_t index = if_nametoindex(if_name.c_str());
+  if (index == 0) {
+    // Try the alternate name. This will be renamed to our preferred name
+    // by the kernel, because we specify IFLA_IFNAME, but open by index.
+    LOG(ERROR) << "Failed to get interface (" << if_name << ") index, "
+               << "trying alternate.";
+    index = if_nametoindex(if_name_alt.c_str());
+    if (index == 0) {
+      LOG(ERROR) << "Failed to get interface (" << if_name_alt << ") index.";
+      return iface;
+    }
   }
 
   iface.reset(new NetworkInterface(index));
diff --git a/common/libs/net/network_interface_manager.h b/common/libs/net/network_interface_manager.h
index 3d6ccc5..f28b0ff 100644
--- a/common/libs/net/network_interface_manager.h
+++ b/common/libs/net/network_interface_manager.h
@@ -32,14 +32,15 @@
 //
 //   std::unique_ptr<NetlinkClient> client(NetlinkClient::GetDefault());
 //   NetworkInterfaceManager manager(client.get());
-//   std::unique_ptr<NetworkInterface> iface(manager.Open("eth0"));
+//   std::unique_ptr<NetworkInterface> iface(manager.Open("eth0", "em0"));
 //
 class NetworkInterfaceManager {
  public:
   // Open existing network interface.
   //
   // NOTE: this method does not fill in any NetworkInterface details yet.
-  std::unique_ptr<NetworkInterface> Open(const std::string& if_name);
+  std::unique_ptr<NetworkInterface> Open(const std::string& if_name,
+                                         const std::string& if_name_alt);
 
   // Apply changes made to existing network interface.
   // This method cannot be used to instantiate new network interfaces.
diff --git a/common/libs/strings/Android.bp b/common/libs/strings/Android.bp
new file mode 100644
index 0000000..273c79e
--- /dev/null
+++ b/common/libs/strings/Android.bp
@@ -0,0 +1,25 @@
+//
+// 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.
+
+cc_library_shared {
+    name: "libcuttlefish_strings",
+    srcs: [
+        "str_split.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+    ],
+    defaults: ["cuttlefish_host_and_guest"],
+}
diff --git a/common/libs/strings/str_split.cpp b/common/libs/strings/str_split.cpp
new file mode 100644
index 0000000..d76acad
--- /dev/null
+++ b/common/libs/strings/str_split.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#include "common/libs/strings/str_split.h"
+
+#include <vector>
+#include <string>
+#include <sstream>
+
+std::vector<std::string> cvd::StrSplit(const std::string& src, char delimiter) {
+  std::istringstream stream{src};
+  std::vector<std::string> result;
+  for (std::string s; std::getline(stream, s, delimiter); s.clear()) {
+    result.push_back(std::move(s));
+  }
+  return result;
+}
diff --git a/common/libs/strings/str_split.h b/common/libs/strings/str_split.h
new file mode 100644
index 0000000..cd18d15
--- /dev/null
+++ b/common/libs/strings/str_split.h
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#ifndef CUTTLEFISH_COMMON_COMMON_LIBS_STRINGS_STR_SPLIT_H_
+#define CUTTLEFISH_COMMON_COMMON_LIBS_STRINGS_STR_SPLIT_H_
+
+#include <vector>
+#include <string>
+
+namespace cvd {
+std::vector<std::string> StrSplit(const std::string& src, char delimiter);
+}  // namespace cvd
+
+#endif
diff --git a/guest/commands/vport_trigger/Android.mk b/guest/commands/vport_trigger/Android.mk
new file mode 100644
index 0000000..e994ce9
--- /dev/null
+++ b/guest/commands/vport_trigger/Android.mk
@@ -0,0 +1,26 @@
+# 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_MODULE := vport_trigger
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := main.cpp
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_MULTILIB := first
+LOCAL_VENDOR_MODULE := true
+
+include $(BUILD_EXECUTABLE)
diff --git a/guest/commands/vport_trigger/main.cpp b/guest/commands/vport_trigger/main.cpp
new file mode 100644
index 0000000..9e4a5f7
--- /dev/null
+++ b/guest/commands/vport_trigger/main.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#include <cutils/properties.h>
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <climits>
+#include <sstream>
+#include <string>
+
+// Taken from android::base, which wasn't available on platform versions
+// earlier than nougat.
+
+static bool ReadFdToString(int fd, std::string* content) {
+  content->clear();
+  char buf[BUFSIZ];
+  ssize_t n;
+  while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
+    content->append(buf, n);
+  }
+  return (n == 0) ? true : false;
+}
+
+static bool ReadFileToString(const std::string& path, std::string* content,
+                             bool follow_symlinks) {
+  int flags = O_RDONLY | O_CLOEXEC | (follow_symlinks ? 0 : O_NOFOLLOW);
+  int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags));
+  if (fd == -1) {
+    return false;
+  }
+  bool result = ReadFdToString(fd, content);
+  close(fd);
+  return result;
+}
+
+int main(int argc __unused, char *argv[] __unused) {
+  // QEMU seems to create on either bus 0 or bus 1.
+  for (size_t bus = 0; bus < 2U; bus++) {
+    // 'max_ports' is set to '31' upstream.
+    for (size_t port = 0; port < 31U; port++) {
+      std::ostringstream vport;
+      vport << "vport" << bus << "p" << port;
+      std::string sysfs("/sys/class/virtio-ports/" + vport.str() + "/name");
+      struct stat st;
+      if (stat(sysfs.c_str(), &st)) {
+        continue;
+      }
+      std::string content;
+      if (!ReadFileToString(sysfs, &content, true)) {
+        continue;
+      }
+      if (content.empty()) {
+        continue;
+      }
+      content.erase(content.end() - 1);
+      // Leaves 32-11=22 characters for the port name from QEMU.
+      std::string propname("sys.cf.ser." + content);
+      std::string dev("/dev/" + vport.str());
+      property_set(propname.c_str(), dev.c_str());
+    }
+  }
+  return 0;
+}
diff --git a/guest/hals/health/health_service.cpp b/guest/hals/health/health_service.cpp
index ae3d28f..48c2571 100644
--- a/guest/hals/health/health_service.cpp
+++ b/guest/hals/health/health_service.cpp
@@ -28,7 +28,7 @@
 
 int healthd_board_battery_update(
     struct android::BatteryProperties* battery_props) {
-  battery_props->chargerAcOnline = false;
+  battery_props->chargerAcOnline = true;
   battery_props->chargerUsbOnline = true;
   battery_props->chargerWirelessOnline = false;
   battery_props->maxChargingCurrent = 500000;
diff --git a/guest/hals/ril/vsoc_ril.cpp b/guest/hals/ril/vsoc_ril.cpp
index b60ad8d..0d33dd9 100644
--- a/guest/hals/ril/vsoc_ril.cpp
+++ b/guest/hals/ril/vsoc_ril.cpp
@@ -114,9 +114,10 @@
   std::unique_ptr<cvd::NetlinkClient> nl(factory->New(NETLINK_ROUTE));
   std::unique_ptr<cvd::NetworkInterfaceManager> nm(
       cvd::NetworkInterfaceManager::New(factory));
-  std::unique_ptr<cvd::NetworkInterface> ni(nm->Open("rmnet0"));
+  std::unique_ptr<cvd::NetworkInterface> ni(nm->Open("rmnet0", "eth0"));
 
   if (ni) {
+    ni->SetName("rmnet0");
     ni->SetAddress(ipaddr);
     ni->SetBroadcastAddress(bcaddr);
     ni->SetPrefixLength(prefixlen);
@@ -132,7 +133,7 @@
 // This call returns true, if operation was successful.
 bool TearDownNetworkInterface() {
   auto nm(cvd::NetworkInterfaceManager::New(nullptr));
-  auto ni(nm->Open("rmnet0"));
+  auto ni(nm->Open("rmnet0", "eth0"));
 
   if (ni) {
     ni->SetOperational(false);
diff --git a/host/commands/launch/Android.bp b/host/commands/launch/Android.bp
index c6b2163..f888d79 100644
--- a/host/commands/launch/Android.bp
+++ b/host/commands/launch/Android.bp
@@ -12,6 +12,7 @@
     shared_libs: [
         "vsoc_lib",
         "libcuttlefish_fs",
+        "libcuttlefish_strings",
         "cuttlefish_auto_resources",
         "libicuuc",
         "libbase",
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index eacd5da..416ebf1 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -22,15 +22,19 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <fstream>
 #include <iomanip>
 #include <memory>
 #include <sstream>
+#include <string>
+#include <vector>
 
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 
 #include "common/libs/fs/shared_select.h"
+#include "common/libs/strings/str_split.h"
 #include "host/commands/launch/pre_launch_initializers.h"
 #include "host/libs/config/file_partition.h"
 #include "host/libs/config/guest_config.h"
@@ -112,17 +116,12 @@
               StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) +
                   "/bin/vnc_server",
               "Location of the vnc server binary.");
-DEFINE_int32(vnc_server_port, vsoc::GetPerInstanceDefault(6444),
+DEFINE_int32(vnc_server_port, GetPerInstanceDefault(6444),
              "The port on which the vnc server should listen");
 DEFINE_string(socket_forward_proxy_binary,
               StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) +
                   "/bin/socket_forward_proxy",
               "Location of the socket_forward_proxy binary.");
-DEFINE_string(socket_forward_proxy_ports, "5555", "Comma-separated list of "
-              "ports on which to run the socket_forward_proxy server. These "
-              "are the port numbers of the guest-side process. The "
-              "host-side socket_forward_proxy process will bias the port "
-              "numbers.");
 
 DEFINE_bool(start_wifi_relay, true, "Whether to start the wifi_relay process.");
 DEFINE_string(wifi_relay_binary,
@@ -309,6 +308,20 @@
     "/bin/rm", "-f", file.c_str(), NULL};
   subprocess(rm_command, NULL);
 }
+
+
+// Emulators are discovered on odd numbered ports from 5555 to 5585
+constexpr int kFirstEmulatorPort = 5555;
+
+std::string GetGuestPortArg() {
+  return std::string{"--guest_ports="} + std::to_string(kFirstEmulatorPort);
+}
+
+std::string GetHostPortArg() {
+  return std::string{"--host_ports="} +
+      std::to_string(kFirstEmulatorPort + (vsoc::GetDefaultInstance() - 1) * 2);
+}
+
 }  // anonymous namespace
 
 int main(int argc, char** argv) {
@@ -419,9 +432,14 @@
 
   std::string entropy_source = "/dev/urandom";
 
-  auto port_arg = std::string{"--ports="} + FLAGS_socket_forward_proxy_ports;
+  auto guest_port_arg = GetGuestPortArg();
+  auto host_port_arg = GetHostPortArg();
+
   const char* const socket_proxy[] =
-    {FLAGS_socket_forward_proxy_binary.c_str(), port_arg.c_str(), NULL};
+    {FLAGS_socket_forward_proxy_binary.c_str(),
+     guest_port_arg.c_str(),
+     host_port_arg.c_str(),
+     NULL};
   subprocess(socket_proxy, nullptr, false);
 
   config::GuestConfig cfg;
diff --git a/host/libs/config/host_config.cpp b/host/libs/config/host_config.cpp
index cc0218d..df39bb6 100644
--- a/host/libs/config/host_config.cpp
+++ b/host/libs/config/host_config.cpp
@@ -16,21 +16,29 @@
 
 #include "host/libs/config/host_config.h"
 
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
 #include <string>
 #include <iomanip>
 #include <sstream>
 
 #include <gflags/gflags.h>
 
-const char kVsocUserPrefix[] = "vsoc-";
-const char kDefaultUuidPrefix[] = "699acfc4-c8c4-11e7-882b-5065f31dc1";
+constexpr char kDefaultUuidPrefix[] = "699acfc4-c8c4-11e7-882b-5065f31dc1";
 
-int GetDefaultInstance() {
-  char* user = getenv("USER");
-  if (user && !memcmp(user, kVsocUserPrefix, sizeof(kVsocUserPrefix) - 1)) {
-    int temp = atoi(user + sizeof(kVsocUserPrefix) - 1);
+DEFINE_string(domain, vsoc::GetDefaultShmClientSocketPath(),
+              "Path to the ivshmem client socket");
+DEFINE_int32(instance, vsoc::GetDefaultInstance(),
+             "Instance number. Must be unique.");
+DEFINE_string(uuid, vsoc::GetPerInstanceDefault(kDefaultUuidPrefix).c_str(),
+              "UUID to use for the device. Random if not specified");
+
+int vsoc::GetDefaultInstance() {
+  static constexpr char kVsocUserPrefix[] = "vsoc-";
+  const char* user = std::getenv("USER");
+  if (user && !std::strncmp(user, kVsocUserPrefix,
+                            sizeof(kVsocUserPrefix) - 1)) {
+    int temp = std::atoi(user + sizeof(kVsocUserPrefix) - 1);
     if (temp > 0) {
       return temp;
     }
@@ -38,13 +46,6 @@
   return 1;
 }
 
-DEFINE_string(domain, vsoc::GetDefaultShmClientSocketPath(),
-              "Path to the ivshmem client socket");
-DEFINE_int32(instance, GetDefaultInstance(),
-             "Instance number. Must be unique.");
-DEFINE_string(uuid, vsoc::GetPerInstanceDefault(kDefaultUuidPrefix).c_str(),
-              "UUID to use for the device. Random if not specified");
-
 std::string vsoc::GetPerInstanceDefault(const char* prefix) {
   std::ostringstream stream;
   stream << prefix << std::setfill('0') << std::setw(2)
diff --git a/host/libs/config/host_config.h b/host/libs/config/host_config.h
index 65ef523..15d2059 100644
--- a/host/libs/config/host_config.h
+++ b/host/libs/config/host_config.h
@@ -21,6 +21,7 @@
 #include <string>
 
 namespace vsoc {
+int GetDefaultInstance();
 std::string GetPerInstanceDefault(const char* prefix);
 int GetPerInstanceDefault(int base);
 std::string GetDefaultPerInstanceDir();