15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/exported_object.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/bus.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/message.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/object_path.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/scoped_dbus_error.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace dbus {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used for success ratio histograms. 1 for success, 0 for failure.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSuccessRatioHistogramMaxValue = 2;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the absolute method name by concatenating the interface name and
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the method name. Used for building keys for method_table_ in
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ExportedObject.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetAbsoluteMethodName(
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& interface_name,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& method_name) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return interface_name + "." + method_name;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExportedObject::ExportedObject(Bus* bus,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const ObjectPath& object_path)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : bus_(bus),
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      object_path_(object_path),
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      object_is_registered_(false) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExportedObject::~ExportedObject() {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!object_is_registered_);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExportedObject::ExportMethodAndBlock(
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& interface_name,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& method_name,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MethodCallCallback method_call_callback) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->AssertOnDBusThread();
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if the method is already exported.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string absolute_method_name =
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetAbsoluteMethodName(interface_name, method_name);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (method_table_.find(absolute_method_name) != method_table_.end()) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << absolute_method_name << " is already exported";
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bus_->Connect())
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bus_->SetUpAsyncOperations())
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!Register())
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the method callback to the method table.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  method_table_[absolute_method_name] = method_call_callback;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExportedObject::ExportMethod(const std::string& interface_name,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const std::string& method_name,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  MethodCallCallback method_call_callback,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  OnExportedCallback on_exported_calback) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->AssertOnOriginThread();
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Closure task = base::Bind(&ExportedObject::ExportMethodInternal,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  this,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  interface_name,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  method_name,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  method_call_callback,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  on_exported_calback);
8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExportedObject::SendSignal(Signal* signal) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For signals, the object path should be set to the path to the sender
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // object, which is this exported object here.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(signal->SetPath(object_path_));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Increment the reference count so we can safely reference the
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // underlying signal message until the signal sending is complete. This
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be unref'ed in SendSignalInternal().
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DBusMessage* signal_message = signal->raw_message();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dbus_message_ref(signal_message);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::TimeTicks start_time = base::TimeTicks::Now();
10268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bus_->GetDBusTaskRunner()->PostTask(
10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      FROM_HERE,
10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      base::Bind(&ExportedObject::SendSignalInternal,
10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                 this,
10668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                 start_time,
10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                 signal_message));
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExportedObject::Unregister() {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->AssertOnDBusThread();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!object_is_registered_)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->UnregisterObjectPath(object_path_);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  object_is_registered_ = false;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExportedObject::ExportMethodInternal(
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& interface_name,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& method_name,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MethodCallCallback method_call_callback,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnExportedCallback on_exported_calback) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->AssertOnDBusThread();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool success = ExportMethodAndBlock(interface_name,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            method_name,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            method_call_callback);
13068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
13168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                        base::Bind(&ExportedObject::OnExported,
13268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                   this,
13368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                   on_exported_calback,
13468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                   interface_name,
13568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                   method_name,
13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                   success));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExportedObject::OnExported(OnExportedCallback on_exported_callback,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& interface_name,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& method_name,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                bool success) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->AssertOnOriginThread();
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  on_exported_callback.Run(interface_name, method_name, success);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExportedObject::SendSignalInternal(base::TimeTicks start_time,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        DBusMessage* signal_message) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 serial = 0;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->Send(signal_message, &serial);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dbus_message_unref(signal_message);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record time spent to send the the signal. This is not accurate as the
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // signal will actually be sent from the next run of the message loop,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // but we can at least tell the number of signals sent.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("DBus.SignalSendTime",
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      base::TimeTicks::Now() - start_time);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExportedObject::Register() {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->AssertOnDBusThread();
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (object_is_registered_)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedDBusError error;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DBusObjectPathVTable vtable = {};
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  vtable.message_function = &ExportedObject::HandleMessageThunk;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  vtable.unregister_function = &ExportedObject::OnUnregisteredThunk;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool success = bus_->TryRegisterObjectPath(object_path_,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   &vtable,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   this,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   error.get());
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!success) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to register the object: " << object_path_.value()
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << ": " << (error.is_set() ? error.message() : "");
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  object_is_registered_ = true;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DBusHandlerResult ExportedObject::HandleMessage(
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DBusConnection* connection,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DBusMessage* raw_message) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->AssertOnDBusThread();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_CALL, dbus_message_get_type(raw_message));
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // raw_message will be unrefed on exit of the function. Increment the
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reference so we can use it in MethodCall.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dbus_message_ref(raw_message);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<MethodCall> method_call(
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MethodCall::FromRawMessage(raw_message));
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string interface = method_call->GetInterface();
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string member = method_call->GetMember();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (interface.empty()) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't support method calls without interface.
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Interface is missing: " << method_call->ToString();
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if we know about the method.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string absolute_method_name = GetAbsoluteMethodName(
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      interface, member);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MethodTable::const_iterator iter = method_table_.find(absolute_method_name);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter == method_table_.end()) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Don't know about the method.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Unknown method: " << method_call->ToString();
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::TimeTicks start_time = base::TimeTicks::Now();
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bus_->HasDBusThread()) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Post a task to run the method in the origin thread.
21868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
21968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                          base::Bind(&ExportedObject::RunMethod,
22068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                     this,
22168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                     iter->second,
22268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                     base::Passed(&method_call),
22368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                                     start_time));
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the D-Bus thread is not used, just call the method directly.
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MethodCall* method = method_call.get();
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    iter->second.Run(method,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     base::Bind(&ExportedObject::SendResponse,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                this,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                start_time,
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                base::Passed(&method_call)));
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It's valid to say HANDLED here, and send a method response at a later
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // time from OnMethodCompleted() asynchronously.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DBUS_HANDLER_RESULT_HANDLED;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExportedObject::RunMethod(MethodCallCallback method_call_callback,
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               scoped_ptr<MethodCall> method_call,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::TimeTicks start_time) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->AssertOnOriginThread();
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MethodCall* method = method_call.get();
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  method_call_callback.Run(method,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           base::Bind(&ExportedObject::SendResponse,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      this,
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      start_time,
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      base::Passed(&method_call)));
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExportedObject::SendResponse(base::TimeTicks start_time,
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  scoped_ptr<MethodCall> method_call,
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  scoped_ptr<Response> response) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(method_call);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bus_->HasDBusThread()) {
25668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    bus_->GetDBusTaskRunner()->PostTask(
25768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        FROM_HERE,
25868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        base::Bind(&ExportedObject::OnMethodCompleted,
25968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                   this,
26068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                   base::Passed(&method_call),
26168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                   base::Passed(&response),
26268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                   start_time));
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OnMethodCompleted(method_call.Pass(), response.Pass(), start_time);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExportedObject::OnMethodCompleted(scoped_ptr<MethodCall> method_call,
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       scoped_ptr<Response> response,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       base::TimeTicks start_time) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->AssertOnDBusThread();
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record if the method call is successful, or not. 1 if successful.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("DBus.ExportedMethodHandleSuccess",
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            response ? 1 : 0,
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kSuccessRatioHistogramMaxValue);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if the bus is still connected. If the method takes long to
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // complete, the bus may be shut down meanwhile.
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bus_->is_connected())
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!response) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Something bad happened in the method call.
2857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    scoped_ptr<ErrorResponse> error_response(
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ErrorResponse::FromMethodCall(
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            method_call.get(),
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            DBUS_ERROR_FAILED,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "error occurred in " + method_call->GetMember()));
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bus_->Send(error_response->raw_message(), NULL);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The method call was successful.
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bus_->Send(response->raw_message(), NULL);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record time spent to handle the the method call. Don't include failures.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("DBus.ExportedMethodHandleTime",
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      base::TimeTicks::Now() - start_time);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExportedObject::OnUnregistered(DBusConnection* connection) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DBusHandlerResult ExportedObject::HandleMessageThunk(
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DBusConnection* connection,
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DBusMessage* raw_message,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* user_data) {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return self->HandleMessage(connection, raw_message);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExportedObject::OnUnregisteredThunk(DBusConnection *connection,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         void* user_data) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return self->OnUnregistered(connection);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace dbus
320