text: // Copyright 2017 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 "debugd/src/helpers/system_service_proxy.h"
  
  #include <base/memory/ptr_util.h>
  #include <dbus/values_util.h>
  
  namespace debugd {
  
  namespace {
  
  const char kDBusPropertiesInterface[] = "org.freedesktop.DBus.Properties";
  const char kDBusPropertiesGetAllMethod[] = "GetAll";
  
  }  // namespace
  
  // static
  std::unique_ptr<SystemServiceProxy> SystemServiceProxy::Create(
      const std::string& service_name) {
    scoped_refptr<dbus::Bus> bus = ConnectToSystemBus();
    if (!bus)
      return nullptr;
  
    return std::unique_ptr<SystemServiceProxy>(
        new SystemServiceProxy(bus, service_name));
  }
  
  SystemServiceProxy::SystemServiceProxy(scoped_refptr<dbus::Bus> bus,
                                         const std::string& service_name)
      : bus_(bus), service_name_(service_name) {}
  
  // static
  scoped_refptr<dbus::Bus> SystemServiceProxy::ConnectToSystemBus() {
    dbus::Bus::Options options;
    options.bus_type = dbus::Bus::SYSTEM;
    scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
    if (!bus->Connect())
      return nullptr;
  
    return bus;
  }
  
  std::unique_ptr<base::Value> SystemServiceProxy::CallMethodAndGetResponse(
      const dbus::ObjectPath& object_path, dbus::MethodCall* method_call) {
    dbus::ObjectProxy* object_proxy =
        bus_->GetObjectProxy(service_name_, object_path);
    std::unique_ptr<dbus::Response> response = object_proxy->CallMethodAndBlock(
        method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
    if (!response)
      return nullptr;
  
    dbus::MessageReader reader(response.get());
    // TODO(benchan): Remove base::WrapUnique() once dbus::PopDataAsValue()
    // returns std::unique_ptr<base::Value> instead of base::Value* when we
    // update libchrome to a new revision.
    return base::WrapUnique(dbus::PopDataAsValue(&reader));
  }
  
  std::unique_ptr<base::DictionaryValue> SystemServiceProxy::GetProperties(
      const std::string& interface_name, const dbus::ObjectPath& object_path) {
    dbus::MethodCall method_call(kDBusPropertiesInterface,
                                 kDBusPropertiesGetAllMethod);
    dbus::MessageWriter writer(&method_call);
    writer.AppendString(interface_name);
    return base::DictionaryValue::From(
        CallMethodAndGetResponse(object_path, &method_call));
  }
  
  std::unique_ptr<base::DictionaryValue>
  SystemServiceProxy::BuildObjectPropertiesMap(
      const std::string& interface_name,
      const std::vector<dbus::ObjectPath>& object_paths) {
    auto result = base::MakeUnique<base::DictionaryValue>();
    for (const auto& object_path : object_paths) {
      result->SetWithoutPathExpansion(object_path.value(),
                                      GetProperties(interface_name, object_path));
    }
    return result;
  }
  
  // static
  std::vector<dbus::ObjectPath> SystemServiceProxy::GetObjectPaths(
      const base::DictionaryValue& properties, const std::string& property_name) {
    std::vector<dbus::ObjectPath> object_paths;
    const base::ListValue* paths = nullptr;
    if (properties.GetList(property_name, &paths)) {
      for (size_t i = 0; i < paths->GetSize(); ++i) {
        std::string path;
        if (paths->GetString(i, &path)) {
          object_paths.emplace_back(path);
        }
      }
    }
    return object_paths;
  }
  
  }  // namespace debugd
  