-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <utility>
-#include "base/bind.h"
+#include "base/containers/contains.h"
+#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/task_runner.h"
#include "base/threading/thread_restrictions.h"
-#include "base/time/time.h"
#include "dbus/bus.h"
+#include "dbus/error.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/scoped_dbus_error.h"
namespace dbus {
-namespace {
-
-// Used for success ratio histograms. 1 for success, 0 for failure.
-const int kSuccessRatioHistogramMaxValue = 2;
-
-} // namespace
-
ExportedObject::ExportedObject(Bus* bus,
const ObjectPath& object_path)
: bus_(bus),
bool ExportedObject::ExportMethodAndBlock(
const std::string& interface_name,
const std::string& method_name,
- MethodCallCallback method_call_callback) {
+ const MethodCallCallback& method_call_callback) {
bus_->AssertOnDBusThread();
// Check if the method is already exported.
const std::string absolute_method_name =
GetAbsoluteMemberName(interface_name, method_name);
- if (method_table_.find(absolute_method_name) != method_table_.end()) {
+ if (base::Contains(method_table_, absolute_method_name)) {
LOG(ERROR) << absolute_method_name << " is already exported";
return false;
}
return true;
}
-void ExportedObject::ExportMethod(const std::string& interface_name,
- const std::string& method_name,
- MethodCallCallback method_call_callback,
- OnExportedCallback on_exported_calback) {
+bool ExportedObject::UnexportMethodAndBlock(const std::string& interface_name,
+ const std::string& method_name) {
+ bus_->AssertOnDBusThread();
+
+ const std::string absolute_method_name =
+ GetAbsoluteMemberName(interface_name, method_name);
+ MethodTable::const_iterator iter = method_table_.find(absolute_method_name);
+ if (iter == method_table_.end()) {
+ LOG(ERROR) << absolute_method_name << " is not exported";
+ return false;
+ }
+
+ method_table_.erase(iter);
+
+ return true;
+}
+
+void ExportedObject::ExportMethod(
+ const std::string& interface_name,
+ const std::string& method_name,
+ const MethodCallCallback& method_call_callback,
+ OnExportedCallback on_exported_callback) {
bus_->AssertOnOriginThread();
- base::Closure task = base::Bind(&ExportedObject::ExportMethodInternal,
- this,
- interface_name,
- method_name,
- method_call_callback,
- on_exported_calback);
- bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
+ base::OnceClosure task = base::BindOnce(
+ &ExportedObject::ExportMethodInternal, this, interface_name, method_name,
+ method_call_callback, std::move(on_exported_callback));
+ bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, std::move(task));
+}
+
+void ExportedObject::UnexportMethod(
+ const std::string& interface_name,
+ const std::string& method_name,
+ OnUnexportedCallback on_unexported_callback) {
+ bus_->AssertOnOriginThread();
+
+ base::OnceClosure task = base::BindOnce(
+ &ExportedObject::UnexportMethodInternal, this, interface_name,
+ method_name, std::move(on_unexported_callback));
+ bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, std::move(task));
}
void ExportedObject::SendSignal(Signal* signal) {
DBusMessage* signal_message = signal->raw_message();
dbus_message_ref(signal_message);
- const base::TimeTicks start_time = base::TimeTicks::Now();
if (bus_->GetDBusTaskRunner()->RunsTasksInCurrentSequence()) {
// The Chrome OS power manager doesn't use a dedicated TaskRunner for
// sending DBus messages. Sending signals asynchronously can cause an
// inversion in the message order if the power manager calls
// ObjectProxy::CallMethodAndBlock() before going back to the top level of
// the MessageLoop: crbug.com/472361.
- SendSignalInternal(start_time, signal_message);
+ SendSignalInternal(signal_message);
} else {
bus_->GetDBusTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ExportedObject::SendSignalInternal,
- this,
- start_time,
- signal_message));
+ FROM_HERE, base::BindOnce(&ExportedObject::SendSignalInternal, this,
+ signal_message));
}
}
void ExportedObject::ExportMethodInternal(
const std::string& interface_name,
const std::string& method_name,
- MethodCallCallback method_call_callback,
- OnExportedCallback on_exported_calback) {
+ const MethodCallCallback& method_call_callback,
+ OnExportedCallback on_exported_callback) {
bus_->AssertOnDBusThread();
const bool success = ExportMethodAndBlock(interface_name,
method_name,
method_call_callback);
- bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
- base::Bind(&ExportedObject::OnExported,
- this,
- on_exported_calback,
- interface_name,
- method_name,
- success));
+ bus_->GetOriginTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&ExportedObject::OnExported, this,
+ std::move(on_exported_callback), interface_name,
+ method_name, success));
+}
+
+void ExportedObject::UnexportMethodInternal(
+ const std::string& interface_name,
+ const std::string& method_name,
+ OnUnexportedCallback on_unexported_callback) {
+ bus_->AssertOnDBusThread();
+
+ const bool success = UnexportMethodAndBlock(interface_name, method_name);
+ bus_->GetOriginTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&ExportedObject::OnUnexported, this,
+ std::move(on_unexported_callback),
+ interface_name, method_name, success));
}
void ExportedObject::OnExported(OnExportedCallback on_exported_callback,
bool success) {
bus_->AssertOnOriginThread();
- on_exported_callback.Run(interface_name, method_name, success);
+ std::move(on_exported_callback).Run(interface_name, method_name, success);
}
-void ExportedObject::SendSignalInternal(base::TimeTicks start_time,
- DBusMessage* signal_message) {
+void ExportedObject::OnUnexported(OnExportedCallback on_unexported_callback,
+ const std::string& interface_name,
+ const std::string& method_name,
+ bool success) {
+ bus_->AssertOnOriginThread();
+
+ std::move(on_unexported_callback).Run(interface_name, method_name, success);
+}
+
+void ExportedObject::SendSignalInternal(DBusMessage* signal_message) {
uint32_t serial = 0;
bus_->Send(signal_message, &serial);
dbus_message_unref(signal_message);
- // Record time spent to send the the signal. This is not accurate as the
- // signal will actually be sent from the next run of the message loop,
- // but we can at least tell the number of signals sent.
- UMA_HISTOGRAM_TIMES("DBus.SignalSendTime",
- base::TimeTicks::Now() - start_time);
}
bool ExportedObject::Register() {
if (object_is_registered_)
return true;
- ScopedDBusError error;
+ Error error;
DBusObjectPathVTable vtable = {};
vtable.message_function = &ExportedObject::HandleMessageThunk;
vtable.unregister_function = &ExportedObject::OnUnregisteredThunk;
- const bool success = bus_->TryRegisterObjectPath(object_path_,
- &vtable,
- this,
- error.get());
+ const bool success =
+ bus_->TryRegisterObjectPath(object_path_, &vtable, this, &error);
if (!success) {
LOG(ERROR) << "Failed to register the object: " << object_path_.value()
- << ": " << (error.is_set() ? error.message() : "");
+ << ": " << error.message();
return false;
}
DBusConnection* connection,
DBusMessage* raw_message) {
bus_->AssertOnDBusThread();
- DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_CALL, dbus_message_get_type(raw_message));
+ // ExportedObject only handles method calls. Ignore other message types (e.g.
+ // signal).
+ if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
// raw_message will be unrefed on exit of the function. Increment the
// reference so we can use it in MethodCall.
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- const base::TimeTicks start_time = base::TimeTicks::Now();
if (bus_->HasDBusThread()) {
// Post a task to run the method in the origin thread.
bus_->GetOriginTaskRunner()->PostTask(
- FROM_HERE,
- base::BindOnce(&ExportedObject::RunMethod, this, iter->second,
- std::move(method_call), start_time));
+ FROM_HERE, base::BindOnce(&ExportedObject::RunMethod, this,
+ iter->second, std::move(method_call)));
} else {
// If the D-Bus thread is not used, just call the method directly.
MethodCall* method = method_call.get();
- iter->second.Run(method,
- base::Bind(&ExportedObject::SendResponse,
- this,
- start_time,
- base::Passed(&method_call)));
+ iter->second.Run(method, base::BindOnce(&ExportedObject::SendResponse, this,
+ std::move(method_call)));
}
// It's valid to say HANDLED here, and send a method response at a later
return DBUS_HANDLER_RESULT_HANDLED;
}
-void ExportedObject::RunMethod(MethodCallCallback method_call_callback,
- std::unique_ptr<MethodCall> method_call,
- base::TimeTicks start_time) {
+void ExportedObject::RunMethod(const MethodCallCallback& method_call_callback,
+ std::unique_ptr<MethodCall> method_call) {
bus_->AssertOnOriginThread();
MethodCall* method = method_call.get();
method_call_callback.Run(method,
- base::Bind(&ExportedObject::SendResponse,
- this,
- start_time,
- base::Passed(&method_call)));
+ base::BindOnce(&ExportedObject::SendResponse, this,
+ std::move(method_call)));
}
-void ExportedObject::SendResponse(base::TimeTicks start_time,
- std::unique_ptr<MethodCall> method_call,
+void ExportedObject::SendResponse(std::unique_ptr<MethodCall> method_call,
std::unique_ptr<Response> response) {
DCHECK(method_call);
if (bus_->HasDBusThread()) {
bus_->GetDBusTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&ExportedObject::OnMethodCompleted, this,
- std::move(method_call), std::move(response),
- start_time));
+ std::move(method_call), std::move(response)));
} else {
- OnMethodCompleted(std::move(method_call), std::move(response), start_time);
+ OnMethodCompleted(std::move(method_call), std::move(response));
}
}
void ExportedObject::OnMethodCompleted(std::unique_ptr<MethodCall> method_call,
- std::unique_ptr<Response> response,
- base::TimeTicks start_time) {
+ std::unique_ptr<Response> response) {
bus_->AssertOnDBusThread();
- // Record if the method call is successful, or not. 1 if successful.
- UMA_HISTOGRAM_ENUMERATION("DBus.ExportedMethodHandleSuccess",
- response ? 1 : 0,
- kSuccessRatioHistogramMaxValue);
-
// Check if the bus is still connected. If the method takes long to
// complete, the bus may be shut down meanwhile.
- if (!bus_->is_connected())
+ if (!bus_->IsConnected())
return;
if (!response) {
// The method call was successful.
bus_->Send(response->raw_message(), nullptr);
-
- // Record time spent to handle the the method call. Don't include failures.
- UMA_HISTOGRAM_TIMES("DBus.ExportedMethodHandleTime",
- base::TimeTicks::Now() - start_time);
}
void ExportedObject::OnUnregistered(DBusConnection* connection) {