1ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat// Use of this source code is governed by a BSD-style license that can be
3ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat// found in the LICENSE file.
4ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
5ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "dbus/exported_object.h"
6ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
70d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <stdint.h>
80d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <utility>
90d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
10ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "base/bind.h"
11ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "base/logging.h"
12ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "base/memory/ref_counted.h"
13ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "base/message_loop/message_loop.h"
14ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "base/metrics/histogram.h"
15ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "base/threading/thread_restrictions.h"
16ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "base/time/time.h"
17ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "dbus/bus.h"
18ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "dbus/message.h"
19ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "dbus/object_path.h"
20ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "dbus/scoped_dbus_error.h"
21ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat#include "dbus/util.h"
22ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
23ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratnamespace dbus {
24ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
25ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratnamespace {
26ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
27ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat// Used for success ratio histograms. 1 for success, 0 for failure.
28ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratconst int kSuccessRatioHistogramMaxValue = 2;
29ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
30ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}  // namespace
31ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
32ae6a045d2239408e25198ad17e2413bdde105788Daniel EratExportedObject::ExportedObject(Bus* bus,
33ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                               const ObjectPath& object_path)
34ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    : bus_(bus),
35ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat      object_path_(object_path),
36ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat      object_is_registered_(false) {
37ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
38ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
39ae6a045d2239408e25198ad17e2413bdde105788Daniel EratExportedObject::~ExportedObject() {
40ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  DCHECK(!object_is_registered_);
41ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
42ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
43ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratbool ExportedObject::ExportMethodAndBlock(
44ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    const std::string& interface_name,
45ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    const std::string& method_name,
46ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    MethodCallCallback method_call_callback) {
47ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->AssertOnDBusThread();
48ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
49ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // Check if the method is already exported.
50ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  const std::string absolute_method_name =
51ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat      GetAbsoluteMemberName(interface_name, method_name);
52ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (method_table_.find(absolute_method_name) != method_table_.end()) {
53ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    LOG(ERROR) << absolute_method_name << " is already exported";
54ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return false;
55ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  }
56ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
57ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (!bus_->Connect())
58ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return false;
59ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (!bus_->SetUpAsyncOperations())
60ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return false;
61ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (!Register())
62ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return false;
63ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
64ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // Add the method callback to the method table.
65ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  method_table_[absolute_method_name] = method_call_callback;
66ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
67ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  return true;
68ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
69ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
70ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratvoid ExportedObject::ExportMethod(const std::string& interface_name,
71ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                  const std::string& method_name,
72ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                  MethodCallCallback method_call_callback,
73ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                  OnExportedCallback on_exported_calback) {
74ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->AssertOnOriginThread();
75ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
76ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  base::Closure task = base::Bind(&ExportedObject::ExportMethodInternal,
77ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                  this,
78ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                  interface_name,
79ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                  method_name,
80ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                  method_call_callback,
81ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                  on_exported_calback);
82ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
83ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
84ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
85ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratvoid ExportedObject::SendSignal(Signal* signal) {
86ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // For signals, the object path should be set to the path to the sender
87ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // object, which is this exported object here.
88ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  CHECK(signal->SetPath(object_path_));
89ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
90ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // Increment the reference count so we can safely reference the
91ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // underlying signal message until the signal sending is complete. This
92ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // will be unref'ed in SendSignalInternal().
93ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  DBusMessage* signal_message = signal->raw_message();
94ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  dbus_message_ref(signal_message);
95ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
96ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  const base::TimeTicks start_time = base::TimeTicks::Now();
97ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (bus_->GetDBusTaskRunner()->RunsTasksOnCurrentThread()) {
98ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    // The Chrome OS power manager doesn't use a dedicated TaskRunner for
99ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    // sending DBus messages.  Sending signals asynchronously can cause an
100ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    // inversion in the message order if the power manager calls
101ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    // ObjectProxy::CallMethodAndBlock() before going back to the top level of
102ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    // the MessageLoop: crbug.com/472361.
103ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    SendSignalInternal(start_time, signal_message);
104ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  } else {
105ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    bus_->GetDBusTaskRunner()->PostTask(
106ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat        FROM_HERE,
107ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat        base::Bind(&ExportedObject::SendSignalInternal,
108ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                   this,
109ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                   start_time,
110ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                   signal_message));
111ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  }
112ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
113ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
114ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratvoid ExportedObject::Unregister() {
115ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->AssertOnDBusThread();
116ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
117ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (!object_is_registered_)
118ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return;
119ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
120ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->UnregisterObjectPath(object_path_);
121ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  object_is_registered_ = false;
122ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
123ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
124ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratvoid ExportedObject::ExportMethodInternal(
125ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    const std::string& interface_name,
126ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    const std::string& method_name,
127ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    MethodCallCallback method_call_callback,
128ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    OnExportedCallback on_exported_calback) {
129ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->AssertOnDBusThread();
130ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
131ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  const bool success = ExportMethodAndBlock(interface_name,
132ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                            method_name,
133ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                            method_call_callback);
134ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
135ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                        base::Bind(&ExportedObject::OnExported,
136ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                   this,
137ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                   on_exported_calback,
138ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                   interface_name,
139ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                   method_name,
140ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                   success));
141ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
142ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
143ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratvoid ExportedObject::OnExported(OnExportedCallback on_exported_callback,
144ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                const std::string& interface_name,
145ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                const std::string& method_name,
146ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                bool success) {
147ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->AssertOnOriginThread();
148ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
149ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  on_exported_callback.Run(interface_name, method_name, success);
150ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
151ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
152ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratvoid ExportedObject::SendSignalInternal(base::TimeTicks start_time,
153ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                        DBusMessage* signal_message) {
1540d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  uint32_t serial = 0;
155ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->Send(signal_message, &serial);
156ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  dbus_message_unref(signal_message);
157ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // Record time spent to send the the signal. This is not accurate as the
158ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // signal will actually be sent from the next run of the message loop,
159ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // but we can at least tell the number of signals sent.
160ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  UMA_HISTOGRAM_TIMES("DBus.SignalSendTime",
161ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                      base::TimeTicks::Now() - start_time);
162ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
163ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
164ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratbool ExportedObject::Register() {
165ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->AssertOnDBusThread();
166ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
167ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (object_is_registered_)
168ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return true;
169ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
170ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  ScopedDBusError error;
171ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
17294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  DBusObjectPathVTable vtable = {};
173ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  vtable.message_function = &ExportedObject::HandleMessageThunk;
174ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  vtable.unregister_function = &ExportedObject::OnUnregisteredThunk;
175ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  const bool success = bus_->TryRegisterObjectPath(object_path_,
176ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                   &vtable,
177ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                   this,
178ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                   error.get());
179ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (!success) {
180ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    LOG(ERROR) << "Failed to register the object: " << object_path_.value()
181ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat               << ": " << (error.is_set() ? error.message() : "");
182ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return false;
183ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  }
184ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
185ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  object_is_registered_ = true;
186ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  return true;
187ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
188ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
18994ffa55491333f3dcc701befd0d2652922916d99Luis Hector ChavezDBusHandlerResult ExportedObject::HandleMessage(DBusConnection*,
19094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez                                                DBusMessage* raw_message) {
191ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->AssertOnDBusThread();
192ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_CALL, dbus_message_get_type(raw_message));
193ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
194ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // raw_message will be unrefed on exit of the function. Increment the
195ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // reference so we can use it in MethodCall.
196ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  dbus_message_ref(raw_message);
19794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  std::unique_ptr<MethodCall> method_call(
198ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat      MethodCall::FromRawMessage(raw_message));
199ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  const std::string interface = method_call->GetInterface();
200ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  const std::string member = method_call->GetMember();
201ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
202ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (interface.empty()) {
203ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    // We don't support method calls without interface.
204ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    LOG(WARNING) << "Interface is missing: " << method_call->ToString();
205ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
206ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  }
207ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
208ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // Check if we know about the method.
209ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  const std::string absolute_method_name = GetAbsoluteMemberName(
210ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat      interface, member);
211ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  MethodTable::const_iterator iter = method_table_.find(absolute_method_name);
212ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (iter == method_table_.end()) {
213ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    // Don't know about the method.
214ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    LOG(WARNING) << "Unknown method: " << method_call->ToString();
215ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
216ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  }
217ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
218ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  const base::TimeTicks start_time = base::TimeTicks::Now();
219ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (bus_->HasDBusThread()) {
220ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    // Post a task to run the method in the origin thread.
221ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
222ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                          base::Bind(&ExportedObject::RunMethod,
223ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                     this,
224ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                     iter->second,
225ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                     base::Passed(&method_call),
226ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                                     start_time));
227ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  } else {
228ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    // If the D-Bus thread is not used, just call the method directly.
229ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    MethodCall* method = method_call.get();
230ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    iter->second.Run(method,
231ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                     base::Bind(&ExportedObject::SendResponse,
232ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                this,
233ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                start_time,
234ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                base::Passed(&method_call)));
235ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  }
236ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
237ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // It's valid to say HANDLED here, and send a method response at a later
238ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // time from OnMethodCompleted() asynchronously.
239ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  return DBUS_HANDLER_RESULT_HANDLED;
240ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
241ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
242ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratvoid ExportedObject::RunMethod(MethodCallCallback method_call_callback,
24394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez                               std::unique_ptr<MethodCall> method_call,
244ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                               base::TimeTicks start_time) {
245ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->AssertOnOriginThread();
246ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  MethodCall* method = method_call.get();
247ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  method_call_callback.Run(method,
248ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                           base::Bind(&ExportedObject::SendResponse,
249ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                      this,
250ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                      start_time,
251ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                      base::Passed(&method_call)));
252ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
253ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
254ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratvoid ExportedObject::SendResponse(base::TimeTicks start_time,
25594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez                                  std::unique_ptr<MethodCall> method_call,
25694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez                                  std::unique_ptr<Response> response) {
257ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  DCHECK(method_call);
258ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (bus_->HasDBusThread()) {
259ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    bus_->GetDBusTaskRunner()->PostTask(
260ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat        FROM_HERE,
261ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat        base::Bind(&ExportedObject::OnMethodCompleted,
262ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                   this,
263ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                   base::Passed(&method_call),
264ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                   base::Passed(&response),
265ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                   start_time));
266ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  } else {
2670d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    OnMethodCompleted(std::move(method_call), std::move(response), start_time);
268ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  }
269ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
270ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
27194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavezvoid ExportedObject::OnMethodCompleted(std::unique_ptr<MethodCall> method_call,
27294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez                                       std::unique_ptr<Response> response,
273ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                       base::TimeTicks start_time) {
274ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->AssertOnDBusThread();
275ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
276ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // Record if the method call is successful, or not. 1 if successful.
277ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  UMA_HISTOGRAM_ENUMERATION("DBus.ExportedMethodHandleSuccess",
278ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                            response ? 1 : 0,
279ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                            kSuccessRatioHistogramMaxValue);
280ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
281ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // Check if the bus is still connected. If the method takes long to
282ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // complete, the bus may be shut down meanwhile.
283ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (!bus_->is_connected())
284ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return;
285ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
286ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  if (!response) {
287ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    // Something bad happened in the method call.
28894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    std::unique_ptr<ErrorResponse> error_response(ErrorResponse::FromMethodCall(
28994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez        method_call.get(), DBUS_ERROR_FAILED,
29094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez        "error occurred in " + method_call->GetMember()));
291ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    bus_->Send(error_response->raw_message(), NULL);
292ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    return;
293ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  }
294ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
295ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // The method call was successful.
296ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  bus_->Send(response->raw_message(), NULL);
297ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
298ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  // Record time spent to handle the the method call. Don't include failures.
299ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  UMA_HISTOGRAM_TIMES("DBus.ExportedMethodHandleTime",
300ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                      base::TimeTicks::Now() - start_time);
301ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
302ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
30394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavezvoid ExportedObject::OnUnregistered(DBusConnection*) {}
304ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
305ae6a045d2239408e25198ad17e2413bdde105788Daniel EratDBusHandlerResult ExportedObject::HandleMessageThunk(
306ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    DBusConnection* connection,
307ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    DBusMessage* raw_message,
308ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat    void* user_data) {
309ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
310ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  return self->HandleMessage(connection, raw_message);
311ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
312ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
313ae6a045d2239408e25198ad17e2413bdde105788Daniel Eratvoid ExportedObject::OnUnregisteredThunk(DBusConnection *connection,
314ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat                                         void* user_data) {
315ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
316ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat  return self->OnUnregistered(connection);
317ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}
318ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat
319ae6a045d2239408e25198ad17e2413bdde105788Daniel Erat}  // namespace dbus
320