1//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "shill/dbus/chromeos_dbus_objectmanager_proxy.h"
18
19#include <memory>
20
21#include "shill/cellular/cellular_error.h"
22#include "shill/event_dispatcher.h"
23#include "shill/logging.h"
24
25using std::string;
26
27namespace shill {
28
29namespace Logging {
30static auto kModuleLogScope = ScopeLogger::kDBus;
31static string ObjectID(const dbus::ObjectPath* p) { return p->value(); }
32}
33
34ChromeosDBusObjectManagerProxy::ChromeosDBusObjectManagerProxy(
35    EventDispatcher* dispatcher,
36    const scoped_refptr<dbus::Bus>& bus,
37    const std::string& path,
38    const std::string& service,
39    const base::Closure& service_appeared_callback,
40    const base::Closure& service_vanished_callback)
41    : proxy_(
42        new org::freedesktop::DBus::ObjectManagerProxy(
43            bus, service, dbus::ObjectPath(path))),
44      dispatcher_(dispatcher),
45      service_appeared_callback_(service_appeared_callback),
46      service_vanished_callback_(service_vanished_callback),
47      service_available_(false) {
48  // Register signal handlers.
49  proxy_->RegisterInterfacesAddedSignalHandler(
50      base::Bind(&ChromeosDBusObjectManagerProxy::InterfacesAdded,
51                 weak_factory_.GetWeakPtr()),
52      base::Bind(&ChromeosDBusObjectManagerProxy::OnSignalConnected,
53                 weak_factory_.GetWeakPtr()));
54  proxy_->RegisterInterfacesRemovedSignalHandler(
55      base::Bind(&ChromeosDBusObjectManagerProxy::InterfacesRemoved,
56                 weak_factory_.GetWeakPtr()),
57      base::Bind(&ChromeosDBusObjectManagerProxy::OnSignalConnected,
58                 weak_factory_.GetWeakPtr()));
59
60  // Monitor service owner changes. This callback lives for the lifetime of
61  // the ObjectProxy.
62  proxy_->GetObjectProxy()->SetNameOwnerChangedCallback(
63      base::Bind(&ChromeosDBusObjectManagerProxy::OnServiceOwnerChanged,
64                 weak_factory_.GetWeakPtr()));
65
66  // One time callback when service becomes available.
67  proxy_->GetObjectProxy()->WaitForServiceToBeAvailable(
68      base::Bind(&ChromeosDBusObjectManagerProxy::OnServiceAvailable,
69                 weak_factory_.GetWeakPtr()));
70}
71
72ChromeosDBusObjectManagerProxy::~ChromeosDBusObjectManagerProxy() {}
73
74void ChromeosDBusObjectManagerProxy::GetManagedObjects(
75    Error* error,
76    const ManagedObjectsCallback& callback,
77    int timeout) {
78  if (!service_available_) {
79    Error::PopulateAndLog(FROM_HERE, error, Error::kInternalError,
80                          "Service not available");
81    return;
82  }
83  proxy_->GetManagedObjectsAsync(
84      base::Bind(&ChromeosDBusObjectManagerProxy::OnGetManagedObjectsSuccess,
85                 weak_factory_.GetWeakPtr(),
86                 callback),
87      base::Bind(&ChromeosDBusObjectManagerProxy::OnGetManagedObjectsFailure,
88                 weak_factory_.GetWeakPtr(),
89                 callback));
90}
91
92void ChromeosDBusObjectManagerProxy::OnServiceAvailable(bool available) {
93  LOG(INFO) << __func__ << ": " << available;
94
95  // The callback might invoke calls to the ObjectProxy, so defer the callback
96  // to event loop.
97  if (available && !service_appeared_callback_.is_null()) {
98    dispatcher_->PostTask(service_appeared_callback_);
99  } else if (!available && !service_vanished_callback_.is_null()) {
100    dispatcher_->PostTask(service_vanished_callback_);
101  }
102  service_available_ = available;
103}
104
105void ChromeosDBusObjectManagerProxy::OnServiceOwnerChanged(
106    const string& old_owner, const string& new_owner) {
107  LOG(INFO) << __func__ << " old: " << old_owner << " new: " << new_owner;
108  if (new_owner.empty()) {
109    OnServiceAvailable(false);
110  } else {
111    OnServiceAvailable(true);
112  }
113}
114
115void ChromeosDBusObjectManagerProxy::OnSignalConnected(
116    const string& interface_name, const string& signal_name, bool success) {
117  SLOG(&proxy_->GetObjectPath(), 2) << __func__
118      << "interface: " << interface_name
119             << " signal: " << signal_name << "success: " << success;
120  if (!success) {
121    LOG(ERROR) << "Failed to connect signal " << signal_name
122        << " to interface " << interface_name;
123  }
124}
125
126void ChromeosDBusObjectManagerProxy::InterfacesAdded(
127    const dbus::ObjectPath& object_path,
128    const DBusInterfaceToProperties& dbus_interface_to_properties) {
129  SLOG(&proxy_->GetObjectPath(), 2) << __func__ << "("
130      << object_path.value() << ")";
131  InterfaceToProperties interface_to_properties;
132  ConvertDBusInterfaceProperties(dbus_interface_to_properties,
133                                 &interface_to_properties);
134  interfaces_added_callback_.Run(object_path.value(), interface_to_properties);
135}
136
137void ChromeosDBusObjectManagerProxy::InterfacesRemoved(
138    const dbus::ObjectPath& object_path,
139    const std::vector<std::string>& interfaces) {
140  SLOG(&proxy_->GetObjectPath(), 2) << __func__ << "("
141      << object_path.value() << ")";
142  interfaces_removed_callback_.Run(object_path.value(), interfaces);
143}
144
145void ChromeosDBusObjectManagerProxy::OnGetManagedObjectsSuccess(
146    const ManagedObjectsCallback& callback,
147    const DBusObjectsWithProperties& dbus_objects_with_properties) {
148  SLOG(&proxy_->GetObjectPath(), 2) << __func__;
149  ObjectsWithProperties objects_with_properties;
150  for (const auto& object : dbus_objects_with_properties) {
151    InterfaceToProperties interface_to_properties;
152    ConvertDBusInterfaceProperties(object.second, &interface_to_properties);
153    objects_with_properties.emplace(object.first.value(),
154                                    interface_to_properties);
155  }
156  callback.Run(objects_with_properties, Error());
157}
158
159void ChromeosDBusObjectManagerProxy::OnGetManagedObjectsFailure(
160    const ManagedObjectsCallback& callback,
161    brillo::Error* dbus_error) {
162  Error error;
163  CellularError::FromChromeosDBusError(dbus_error, &error);
164  callback.Run(ObjectsWithProperties(), error);
165}
166
167void ChromeosDBusObjectManagerProxy::ConvertDBusInterfaceProperties(
168    const DBusInterfaceToProperties& dbus_interface_to_properties,
169    InterfaceToProperties* interface_to_properties) {
170  for (const auto& interface : dbus_interface_to_properties) {
171    KeyValueStore properties;
172    KeyValueStore::ConvertFromVariantDictionary(interface.second, &properties);
173    interface_to_properties->emplace(interface.first, properties);
174  }
175}
176
177}  // namespace shill
178