1// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <brillo/dbus/exported_object_manager.h>
6
7#include <vector>
8
9#include <brillo/dbus/async_event_sequencer.h>
10#include <dbus/object_manager.h>
11
12using brillo::dbus_utils::AsyncEventSequencer;
13
14namespace brillo {
15
16namespace dbus_utils {
17
18ExportedObjectManager::ExportedObjectManager(scoped_refptr<dbus::Bus> bus,
19                                             const dbus::ObjectPath& path)
20    : bus_(bus), dbus_object_(nullptr, bus, path) {
21}
22
23void ExportedObjectManager::RegisterAsync(
24    const AsyncEventSequencer::CompletionAction& completion_callback) {
25  VLOG(1) << "Registering object manager";
26  bus_->AssertOnOriginThread();
27  DBusInterface* itf =
28      dbus_object_.AddOrGetInterface(dbus::kObjectManagerInterface);
29  itf->AddSimpleMethodHandler(dbus::kObjectManagerGetManagedObjects,
30                              base::Unretained(this),
31                              &ExportedObjectManager::HandleGetManagedObjects);
32
33  signal_itf_added_ = itf->RegisterSignalOfType<SignalInterfacesAdded>(
34      dbus::kObjectManagerInterfacesAdded);
35  signal_itf_removed_ = itf->RegisterSignalOfType<SignalInterfacesRemoved>(
36      dbus::kObjectManagerInterfacesRemoved);
37  dbus_object_.RegisterAsync(completion_callback);
38}
39
40void ExportedObjectManager::ClaimInterface(
41    const dbus::ObjectPath& path,
42    const std::string& interface_name,
43    const ExportedPropertySet::PropertyWriter& property_writer) {
44  bus_->AssertOnOriginThread();
45  // We're sending signals that look like:
46  //   org.freedesktop.DBus.ObjectManager.InterfacesAdded (
47  //       OBJPATH object_path,
48  //       DICT<STRING,DICT<STRING,VARIANT>> interfaces_and_properties);
49  VariantDictionary property_dict;
50  property_writer.Run(&property_dict);
51  std::map<std::string, VariantDictionary> interfaces_and_properties{
52      {interface_name, property_dict}
53  };
54  signal_itf_added_.lock()->Send(path, interfaces_and_properties);
55  registered_objects_[path][interface_name] = property_writer;
56}
57
58void ExportedObjectManager::ReleaseInterface(
59    const dbus::ObjectPath& path,
60    const std::string& interface_name) {
61  bus_->AssertOnOriginThread();
62  auto interfaces_for_path_itr = registered_objects_.find(path);
63  CHECK(interfaces_for_path_itr != registered_objects_.end())
64      << "Attempting to signal interface removal for path " << path.value()
65      << " which was never registered.";
66  auto& interfaces_for_path = interfaces_for_path_itr->second;
67  auto property_for_interface_itr = interfaces_for_path.find(interface_name);
68  CHECK(property_for_interface_itr != interfaces_for_path.end())
69      << "Attempted to remove interface " << interface_name << " from "
70      << path.value() << ", but this interface was never registered.";
71  interfaces_for_path.erase(interface_name);
72  if (interfaces_for_path.empty())
73    registered_objects_.erase(path);
74
75  // We're sending signals that look like:
76  //   org.freedesktop.DBus.ObjectManager.InterfacesRemoved (
77  //       OBJPATH object_path, ARRAY<STRING> interfaces);
78  signal_itf_removed_.lock()->Send(path,
79                                   std::vector<std::string>{interface_name});
80}
81
82ExportedObjectManager::ObjectMap
83ExportedObjectManager::HandleGetManagedObjects() {
84  // Implements the GetManagedObjects method:
85  //
86  // org.freedesktop.DBus.ObjectManager.GetManagedObjects (
87  //     out DICT<OBJPATH,
88  //              DICT<STRING,
89  //                   DICT<STRING,VARIANT>>> )
90  bus_->AssertOnOriginThread();
91  ExportedObjectManager::ObjectMap objects;
92  for (const auto path_pair : registered_objects_) {
93    std::map<std::string, VariantDictionary>& interfaces =
94        objects[path_pair.first];
95    const InterfaceProperties& interface2properties = path_pair.second;
96    for (const auto interface : interface2properties) {
97      interface.second.Run(&interfaces[interface.first]);
98    }
99  }
100  return objects;
101}
102
103}  // namespace dbus_utils
104
105}  // namespace brillo
106