arc: Move platform2/arc/network/ to platform2/patchpanel

Next step in the arc-networkd -> patchpanel rename, this patch moves the
location of the code.

BUG=b:151879931
TEST=units,flashed image to atlas
TEST=tasts arc.PlayStore, crostini.LaunchTerminal.download

Change-Id: I1b5cf8d670e1631d46f6449b725395157bf88dde
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2115863
Tested-by: Garrick Evans <garrick@chromium.org>
Commit-Queue: Garrick Evans <garrick@chromium.org>
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Reviewed-by: Eric Caruso <ejcaruso@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Hugo Benichi <hugobenichi@google.com>
diff --git a/patchpanel/shill_client.cc b/patchpanel/shill_client.cc
new file mode 100644
index 0000000..18b0ca5
--- /dev/null
+++ b/patchpanel/shill_client.cc
@@ -0,0 +1,217 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "patchpanel/shill_client.h"
+
+#include <vector>
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/strings/string_util.h>
+#include <chromeos/dbus/service_constants.h>
+
+namespace patchpanel {
+
+ShillClient::ShillClient(const scoped_refptr<dbus::Bus>& bus) : bus_(bus) {
+  manager_proxy_.reset(new org::chromium::flimflam::ManagerProxy(bus_));
+  manager_proxy_->RegisterPropertyChangedSignalHandler(
+      base::Bind(&ShillClient::OnManagerPropertyChange,
+                 weak_factory_.GetWeakPtr()),
+      base::Bind(&ShillClient::OnManagerPropertyChangeRegistration,
+                 weak_factory_.GetWeakPtr()));
+}
+
+const std::string& ShillClient::default_interface() const {
+  return default_interface_;
+}
+
+const std::set<std::string> ShillClient::get_devices() const {
+  return devices_;
+}
+
+bool ShillClient::has_device(const std::string& ifname) const {
+  return devices_.find(ifname) != devices_.end();
+}
+
+void ShillClient::ScanDevices(const DevicesChangeHandler& handler) {
+  brillo::VariantDictionary props;
+  if (!manager_proxy_->GetProperties(&props, nullptr)) {
+    LOG(ERROR) << "Unable to get manager properties";
+    return;
+  }
+  const auto it = props.find(shill::kDevicesProperty);
+  if (it == props.end()) {
+    LOG(WARNING) << "Manager properties is missing devices";
+    return;
+  }
+  UpdateDevices(it->second);
+}
+
+std::string ShillClient::GetDefaultInterface() {
+  brillo::VariantDictionary manager_props;
+
+  if (!manager_proxy_->GetProperties(&manager_props, nullptr)) {
+    LOG(ERROR) << "Unable to get manager properties";
+    return "";
+  }
+
+  auto it = manager_props.find(shill::kDefaultServiceProperty);
+  if (it == manager_props.end()) {
+    LOG(WARNING) << "Manager properties is missing default service";
+    return "";
+  }
+
+  dbus::ObjectPath service_path = it->second.TryGet<dbus::ObjectPath>();
+  if (!service_path.IsValid() || service_path.value() == "/") {
+    return "";
+  }
+
+  org::chromium::flimflam::ServiceProxy service_proxy(bus_, service_path);
+  brillo::VariantDictionary service_props;
+  if (!service_proxy.GetProperties(&service_props, nullptr)) {
+    LOG(ERROR) << "Can't retrieve properties for service";
+    return "";
+  }
+
+  it = service_props.find(shill::kIsConnectedProperty);
+  if (it == service_props.end()) {
+    LOG(WARNING) << "Service properties is missing \"IsConnected\"";
+    return "";
+  }
+  if (!it->second.TryGet<bool>()) {
+    LOG(INFO) << "Ignoring non-connected service";
+    return "";
+  }
+
+  it = service_props.find(shill::kDeviceProperty);
+  if (it == service_props.end()) {
+    LOG(WARNING) << "Service properties is missing device path";
+    return "";
+  }
+
+  dbus::ObjectPath device_path = it->second.TryGet<dbus::ObjectPath>();
+  if (!device_path.IsValid()) {
+    LOG(WARNING) << "Invalid device path";
+    return "";
+  }
+
+  org::chromium::flimflam::DeviceProxy device_proxy(bus_, device_path);
+  brillo::VariantDictionary device_props;
+  if (!device_proxy.GetProperties(&device_props, nullptr)) {
+    LOG(ERROR) << "Can't retrieve properties for device";
+    return "";
+  }
+
+  it = device_props.find(shill::kInterfaceProperty);
+  if (it == device_props.end()) {
+    LOG(WARNING) << "Device properties is missing interface name";
+    return "";
+  }
+
+  std::string interface = it->second.TryGet<std::string>();
+  if (interface.empty()) {
+    LOG(WARNING) << "Device interface name is empty";
+  }
+
+  return interface;
+}
+
+void ShillClient::OnManagerPropertyChangeRegistration(
+    const std::string& interface,
+    const std::string& signal_name,
+    bool success) {
+  if (!success)
+    LOG(FATAL) << "Unable to register for interface change events";
+}
+
+void ShillClient::OnManagerPropertyChange(const std::string& property_name,
+                                          const brillo::Any& property_value) {
+  if (property_name == shill::kDevicesProperty) {
+    UpdateDevices(property_value);
+
+    // Choose a fallback interface when any network device exist. Update the
+    // fallback interface if it that device does not exist anymore.
+    if (!devices_.empty() &&
+        devices_.find(fallback_default_interface_) == devices_.end()) {
+      fallback_default_interface_ = *devices_.begin();
+      // When the system appears to have no default interface, use the fallback
+      // interface instead.
+      if (default_interface_.empty() ||
+          default_interface_ != fallback_default_interface_)
+        SetDefaultInterface(fallback_default_interface_);
+    }
+
+    // Remove the fallback interface when no network device is managed by shill.
+    if (!fallback_default_interface_.empty() && devices_.empty()) {
+      fallback_default_interface_ = "";
+      SetDefaultInterface("");
+    }
+
+    return;
+  }
+
+  if (property_name != shill::kDefaultServiceProperty &&
+      property_name != shill::kConnectionStateProperty)
+    return;
+
+  SetDefaultInterface(GetDefaultInterface());
+}
+
+std::string ShillClient::SetDefaultInterface(std::string new_default) {
+  // When the system default is lost, use the fallback interface instead.
+  if (new_default.empty())
+    new_default = fallback_default_interface_;
+
+  if (default_interface_ == new_default)
+    return default_interface_;
+
+  LOG(INFO) << "Default interface changed from [" << default_interface_
+            << "] to [" << new_default << "]";
+
+  const std::string prev_default = default_interface_;
+  default_interface_ = new_default;
+  for (const auto& h : default_interface_handlers_) {
+    if (!h.is_null())
+      h.Run(default_interface_, prev_default);
+  }
+  return prev_default;
+}
+
+void ShillClient::RegisterDefaultInterfaceChangedHandler(
+    const DefaultInterfaceChangeHandler& handler) {
+  default_interface_handlers_.emplace_back(handler);
+  const auto prev_default = SetDefaultInterface(GetDefaultInterface());
+  handler.Run(default_interface_, prev_default);
+}
+
+void ShillClient::RegisterDevicesChangedHandler(
+    const DevicesChangeHandler& handler) {
+  device_handlers_.emplace_back(handler);
+}
+
+void ShillClient::UpdateDevices(const brillo::Any& property_value) {
+  std::set<std::string> new_devices, added, removed;
+  for (const auto& path :
+       property_value.TryGet<std::vector<dbus::ObjectPath>>()) {
+    std::string device = path.value();
+    // Strip "/device/" prefix.
+    device = device.substr(device.find_last_of('/') + 1);
+
+    new_devices.emplace(device);
+    if (devices_.find(device) == devices_.end())
+      added.insert(device);
+  }
+
+  for (const auto& d : devices_) {
+    if (new_devices.find(d) == new_devices.end())
+      removed.insert(d);
+  }
+
+  devices_ = new_devices;
+
+  for (const auto& h : device_handlers_)
+    h.Run(added, removed);
+}
+
+}  // namespace patchpanel