blob: 441dc757bd707add204cd4b07f53a74edca27b33 [file] [log] [blame]
adamk@chromium.org35c0eef2012-02-11 06:45:23 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
satorux@chromium.org163f1cb2011-08-18 05:58:12 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "dbus/bus.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
avi@chromium.orga29af562013-07-18 08:00:30 +09009#include "base/message_loop/message_loop.h"
satorux@chromium.org5a92cf32011-09-07 05:53:30 +090010#include "base/metrics/histogram.h"
tfarina@chromium.org0eed10b2013-04-18 06:42:40 +090011#include "base/strings/string_piece.h"
avi@chromium.orgffcdb952013-06-11 16:27:01 +090012#include "base/strings/stringprintf.h"
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +090013#include "base/task_runner_util.h"
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090014#include "base/threading/thread.h"
15#include "base/threading/thread_restrictions.h"
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +090016#include "dbus/dbus_statistics.h"
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090017#include "dbus/message.h"
keybuk@google.combf4649a2012-02-15 06:29:06 +090018#include "dbus/object_path.h"
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090019#include "dbus/object_proxy.h"
20#include "dbus/scoped_dbus_error.h"
armansitof4364642014-09-06 02:49:34 +090021#include "dbus/util.h"
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090022
thestig@chromium.org56057f22013-05-05 00:48:37 +090023namespace dbus {
24
satorux@chromium.org7f0c4512011-08-23 16:29:21 +090025namespace {
26
adamk@chromium.org35c0eef2012-02-11 06:45:23 +090027const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown";
stevenjb@chromium.orgc415c482014-08-09 06:57:19 +090028const char kErrorObjectUnknown[] = "org.freedesktop.DBus.Error.UnknownObject";
adamk@chromium.org35c0eef2012-02-11 06:45:23 +090029
satorux@chromium.org5a92cf32011-09-07 05:53:30 +090030// Used for success ratio histograms. 1 for success, 0 for failure.
31const int kSuccessRatioHistogramMaxValue = 2;
32
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +090033// The path of D-Bus Object sending NameOwnerChanged signal.
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +090034const char kDBusSystemObjectPath[] = "/org/freedesktop/DBus";
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +090035
thestig@chromium.org56057f22013-05-05 00:48:37 +090036// The D-Bus Object interface.
37const char kDBusSystemObjectInterface[] = "org.freedesktop.DBus";
38
39// The D-Bus Object address.
40const char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";
41
42// The NameOwnerChanged member in |kDBusSystemObjectInterface|.
43const char kNameOwnerChangedMember[] = "NameOwnerChanged";
44
satorux@chromium.orgb1753152011-11-11 17:36:22 +090045// An empty function used for ObjectProxy::EmptyResponseCallback().
thestig@chromium.org56057f22013-05-05 00:48:37 +090046void EmptyResponseCallbackBody(Response* /*response*/) {
satorux@chromium.orgb1753152011-11-11 17:36:22 +090047}
48
satorux@chromium.org7f0c4512011-08-23 16:29:21 +090049} // namespace
50
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090051ObjectProxy::ObjectProxy(Bus* bus,
52 const std::string& service_name,
keybuk@google.combf4649a2012-02-15 06:29:06 +090053 const ObjectPath& object_path,
adamk@chromium.org35c0eef2012-02-11 06:45:23 +090054 int options)
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090055 : bus_(bus),
56 service_name_(service_name),
satorux@chromium.org7f0c4512011-08-23 16:29:21 +090057 object_path_(object_path),
adamk@chromium.org35c0eef2012-02-11 06:45:23 +090058 ignore_service_unknown_errors_(
59 options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090060}
61
62ObjectProxy::~ObjectProxy() {
hashimoto14eb1502015-03-30 16:01:39 +090063 DCHECK(pending_calls_.empty());
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090064}
65
66// Originally we tried to make |method_call| a const reference, but we
67// gave up as dbus_connection_send_with_reply_and_block() takes a
68// non-const pointer of DBusMessage as the second parameter.
avakulenko1d8962b2014-09-17 10:44:09 +090069scoped_ptr<Response> ObjectProxy::CallMethodAndBlockWithErrorDetails(
70 MethodCall* method_call, int timeout_ms, ScopedDBusError* error) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090071 bus_->AssertOnDBusThread();
72
hashimoto@chromium.orgb0305512012-05-23 15:55:22 +090073 if (!bus_->Connect() ||
74 !method_call->SetDestination(service_name_) ||
75 !method_call->SetPath(object_path_))
yuki@chromium.orgd4eedf82013-02-07 18:46:24 +090076 return scoped_ptr<Response>();
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090077
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090078 DBusMessage* request_message = method_call->raw_message();
79
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090080 // Send the message synchronously.
satorux@chromium.org5a92cf32011-09-07 05:53:30 +090081 const base::TimeTicks start_time = base::TimeTicks::Now();
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090082 DBusMessage* response_message =
avakulenko1d8962b2014-09-17 10:44:09 +090083 bus_->SendWithReplyAndBlock(request_message, timeout_ms, error->get());
satorux@chromium.org5a92cf32011-09-07 05:53:30 +090084 // Record if the method call is successful, or not. 1 if successful.
85 UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
86 response_message ? 1 : 0,
87 kSuccessRatioHistogramMaxValue);
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +090088 statistics::AddBlockingSentMethodCall(service_name_,
89 method_call->GetInterface(),
90 method_call->GetMember());
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090091
92 if (!response_message) {
satorux@chromium.org31bb21e2012-05-31 15:12:11 +090093 LogMethodCallFailure(method_call->GetInterface(),
94 method_call->GetMember(),
avakulenko1d8962b2014-09-17 10:44:09 +090095 error->is_set() ? error->name() : "unknown error type",
96 error->is_set() ? error->message() : "");
yuki@chromium.orgd4eedf82013-02-07 18:46:24 +090097 return scoped_ptr<Response>();
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090098 }
satorux@chromium.org5a92cf32011-09-07 05:53:30 +090099 // Record time spent for the method call. Don't include failures.
100 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
101 base::TimeTicks::Now() - start_time);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900102
satorux@chromium.orgffa83a92011-08-24 12:32:06 +0900103 return Response::FromRawMessage(response_message);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900104}
105
avakulenko1d8962b2014-09-17 10:44:09 +0900106scoped_ptr<Response> ObjectProxy::CallMethodAndBlock(MethodCall* method_call,
107 int timeout_ms) {
108 ScopedDBusError error;
109 return CallMethodAndBlockWithErrorDetails(method_call, timeout_ms, &error);
110}
111
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900112void ObjectProxy::CallMethod(MethodCall* method_call,
113 int timeout_ms,
114 ResponseCallback callback) {
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900115 CallMethodWithErrorCallback(method_call, timeout_ms, callback,
116 base::Bind(&ObjectProxy::OnCallMethodError,
117 this,
satorux@chromium.org31bb21e2012-05-31 15:12:11 +0900118 method_call->GetInterface(),
119 method_call->GetMember(),
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900120 callback));
121}
122
123void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
124 int timeout_ms,
125 ResponseCallback callback,
126 ErrorCallback error_callback) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900127 bus_->AssertOnOriginThread();
128
hashimoto@chromium.orgb0305512012-05-23 15:55:22 +0900129 const base::TimeTicks start_time = base::TimeTicks::Now();
130
131 if (!method_call->SetDestination(service_name_) ||
132 !method_call->SetPath(object_path_)) {
133 // In case of a failure, run the error callback with NULL.
134 DBusMessage* response_message = NULL;
135 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
136 this,
137 callback,
138 error_callback,
139 start_time,
140 response_message);
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900141 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
hashimoto@chromium.orgb0305512012-05-23 15:55:22 +0900142 return;
143 }
144
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900145 // Increment the reference count so we can safely reference the
146 // underlying request message until the method call is complete. This
147 // will be unref'ed in StartAsyncMethodCall().
148 DBusMessage* request_message = method_call->raw_message();
149 dbus_message_ref(request_message);
150
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900151 base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall,
152 this,
153 timeout_ms,
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900154 request_message,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900155 callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900156 error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900157 start_time);
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +0900158 statistics::AddSentMethodCall(service_name_,
159 method_call->GetInterface(),
160 method_call->GetMember());
161
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900162 // Wait for the response in the D-Bus thread.
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900163 bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900164}
165
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900166void ObjectProxy::ConnectToSignal(const std::string& interface_name,
167 const std::string& signal_name,
168 SignalCallback signal_callback,
169 OnConnectedCallback on_connected_callback) {
170 bus_->AssertOnOriginThread();
171
dtapuskad998f172015-01-23 23:41:21 +0900172 if (bus_->HasDBusThread()) {
173 base::PostTaskAndReplyWithResult(
174 bus_->GetDBusTaskRunner(), FROM_HERE,
175 base::Bind(&ObjectProxy::ConnectToSignalInternal, this, interface_name,
176 signal_name, signal_callback),
177 base::Bind(on_connected_callback, interface_name, signal_name));
178 } else {
179 // If the bus doesn't have a dedicated dbus thread we need to call
180 // ConnectToSignalInternal directly otherwise we might miss a signal
181 // that is currently queued if we do a PostTask.
182 const bool success =
183 ConnectToSignalInternal(interface_name, signal_name, signal_callback);
184 on_connected_callback.Run(interface_name, signal_name, success);
185 }
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900186}
187
hashimoto@chromium.org4f3851c2013-09-27 16:12:03 +0900188void ObjectProxy::SetNameOwnerChangedCallback(
189 NameOwnerChangedCallback callback) {
190 bus_->AssertOnOriginThread();
191
192 name_owner_changed_callback_ = callback;
193}
194
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900195void ObjectProxy::WaitForServiceToBeAvailable(
196 WaitForServiceToBeAvailableCallback callback) {
197 bus_->AssertOnOriginThread();
198
199 wait_for_service_to_be_available_callbacks_.push_back(callback);
200 bus_->GetDBusTaskRunner()->PostTask(
201 FROM_HERE,
202 base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal, this));
203}
204
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900205void ObjectProxy::Detach() {
206 bus_->AssertOnDBusThread();
207
hashimoto46be6e92014-12-04 16:41:55 +0900208 if (bus_->is_connected())
209 bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this);
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900210
hashimoto14eb1502015-03-30 16:01:39 +0900211 for (const auto& match_rule : match_rules_) {
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900212 ScopedDBusError error;
hashimoto14eb1502015-03-30 16:01:39 +0900213 bus_->RemoveMatch(match_rule, error.get());
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900214 if (error.is_set()) {
215 // There is nothing we can do to recover, so just print the error.
hashimoto14eb1502015-03-30 16:01:39 +0900216 LOG(ERROR) << "Failed to remove match rule: " << match_rule;
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900217 }
218 }
satorux@chromium.org5b3e4962011-11-24 07:08:38 +0900219 match_rules_.clear();
hashimoto14eb1502015-03-30 16:01:39 +0900220
221 for (auto* pending_call : pending_calls_) {
222 dbus_pending_call_cancel(pending_call);
223 dbus_pending_call_unref(pending_call);
224 }
225 pending_calls_.clear();
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900226}
227
satorux@chromium.orgb1753152011-11-11 17:36:22 +0900228// static
229ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() {
230 return base::Bind(&EmptyResponseCallbackBody);
231}
232
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900233ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
234 ObjectProxy* in_object_proxy,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900235 ResponseCallback in_response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900236 ErrorCallback in_error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900237 base::TimeTicks in_start_time)
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900238 : object_proxy(in_object_proxy),
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900239 response_callback(in_response_callback),
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900240 error_callback(in_error_callback),
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900241 start_time(in_start_time) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900242}
243
244ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
245}
246
247void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900248 DBusMessage* request_message,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900249 ResponseCallback response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900250 ErrorCallback error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900251 base::TimeTicks start_time) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900252 bus_->AssertOnDBusThread();
253
254 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900255 // In case of a failure, run the error callback with NULL.
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900256 DBusMessage* response_message = NULL;
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900257 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
258 this,
259 response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900260 error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900261 start_time,
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900262 response_message);
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900263 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900264
265 dbus_message_unref(request_message);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900266 return;
267 }
268
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900269 DBusPendingCall* pending_call = NULL;
270
271 bus_->SendWithReply(request_message, &pending_call, timeout_ms);
272
273 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
274 // The data will be deleted in OnPendingCallIsCompleteThunk().
275 OnPendingCallIsCompleteData* data =
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900276 new OnPendingCallIsCompleteData(this, response_callback, error_callback,
277 start_time);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900278
279 // This returns false only when unable to allocate memory.
280 const bool success = dbus_pending_call_set_notify(
281 pending_call,
282 &ObjectProxy::OnPendingCallIsCompleteThunk,
283 data,
hashimotob6084f52015-03-30 15:52:21 +0900284 &DeleteVoidPointer<OnPendingCallIsCompleteData>);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900285 CHECK(success) << "Unable to allocate memory";
hashimoto14eb1502015-03-30 16:01:39 +0900286 pending_calls_.insert(pending_call);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900287
288 // It's now safe to unref the request message.
289 dbus_message_unref(request_message);
290}
291
292void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900293 ResponseCallback response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900294 ErrorCallback error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900295 base::TimeTicks start_time) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900296 bus_->AssertOnDBusThread();
297
298 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900299 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
300 this,
301 response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900302 error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900303 start_time,
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900304 response_message);
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900305 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
hashimoto14eb1502015-03-30 16:01:39 +0900306
307 // Remove the pending call from the set.
308 pending_calls_.erase(pending_call);
309 dbus_pending_call_unref(pending_call);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900310}
311
312void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900313 ErrorCallback error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900314 base::TimeTicks start_time,
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900315 DBusMessage* response_message) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900316 bus_->AssertOnOriginThread();
317
satorux@chromium.orgb1753152011-11-11 17:36:22 +0900318 bool method_call_successful = false;
satorux@chromium.orgffa83a92011-08-24 12:32:06 +0900319 if (!response_message) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900320 // The response is not received.
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900321 error_callback.Run(NULL);
satorux@chromium.orgffa83a92011-08-24 12:32:06 +0900322 } else if (dbus_message_get_type(response_message) ==
323 DBUS_MESSAGE_TYPE_ERROR) {
324 // This will take |response_message| and release (unref) it.
thestig@chromium.org56057f22013-05-05 00:48:37 +0900325 scoped_ptr<ErrorResponse> error_response(
326 ErrorResponse::FromRawMessage(response_message));
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900327 error_callback.Run(error_response.get());
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900328 // Delete the message on the D-Bus thread. See below for why.
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900329 bus_->GetDBusTaskRunner()->PostTask(
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900330 FROM_HERE,
thestig@chromium.org56057f22013-05-05 00:48:37 +0900331 base::Bind(&base::DeletePointer<ErrorResponse>,
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900332 error_response.release()));
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900333 } else {
satorux@chromium.orgffa83a92011-08-24 12:32:06 +0900334 // This will take |response_message| and release (unref) it.
thestig@chromium.org56057f22013-05-05 00:48:37 +0900335 scoped_ptr<Response> response(Response::FromRawMessage(response_message));
satorux@chromium.orgc6ac7572011-09-01 03:02:43 +0900336 // The response is successfully received.
satorux@chromium.orgffa83a92011-08-24 12:32:06 +0900337 response_callback.Run(response.get());
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900338 // The message should be deleted on the D-Bus thread for a complicated
339 // reason:
340 //
341 // libdbus keeps track of the number of bytes in the incoming message
342 // queue to ensure that the data size in the queue is manageable. The
343 // bookkeeping is partly done via dbus_message_unref(), and immediately
344 // asks the client code (Chrome) to stop monitoring the underlying
345 // socket, if the number of bytes exceeds a certian number, which is set
346 // to 63MB, per dbus-transport.cc:
347 //
348 // /* Try to default to something that won't totally hose the system,
349 // * but doesn't impose too much of a limitation.
350 // */
351 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
352 //
353 // The monitoring of the socket is done on the D-Bus thread (see Watch
354 // class in bus.cc), hence we should stop the monitoring from D-Bus
355 // thread, not from the current thread here, which is likely UI thread.
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900356 bus_->GetDBusTaskRunner()->PostTask(
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900357 FROM_HERE,
thestig@chromium.org56057f22013-05-05 00:48:37 +0900358 base::Bind(&base::DeletePointer<Response>, response.release()));
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900359
satorux@chromium.orgb1753152011-11-11 17:36:22 +0900360 method_call_successful = true;
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900361 // Record time spent for the method call. Don't include failures.
362 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
363 base::TimeTicks::Now() - start_time);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900364 }
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900365 // Record if the method call is successful, or not. 1 if successful.
366 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
satorux@chromium.orgb1753152011-11-11 17:36:22 +0900367 method_call_successful,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900368 kSuccessRatioHistogramMaxValue);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900369}
370
371void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call,
372 void* user_data) {
373 OnPendingCallIsCompleteData* data =
374 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data);
375 ObjectProxy* self = data->object_proxy;
376 self->OnPendingCallIsComplete(pending_call,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900377 data->response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900378 data->error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900379 data->start_time);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900380}
381
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900382bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900383 bus_->AssertOnDBusThread();
384
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900385 if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
386 return false;
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900387
hashimoto46be6e92014-12-04 16:41:55 +0900388 bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this);
389
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900390 // Add a match_rule listening NameOwnerChanged for the well-known name
391 // |service_name_|.
392 const std::string name_owner_changed_match_rule =
393 base::StringPrintf(
394 "type='signal',interface='org.freedesktop.DBus',"
395 "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
396 "sender='org.freedesktop.DBus',arg0='%s'",
397 service_name_.c_str());
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900398
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900399 const bool success =
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900400 AddMatchRuleWithoutCallback(name_owner_changed_match_rule,
401 "org.freedesktop.DBus.NameOwnerChanged");
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900402
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900403 // Try getting the current name owner. It's not guaranteed that we can get
404 // the name owner at this moment, as the service may not yet be started. If
405 // that's the case, we'll get the name owner via NameOwnerChanged signal,
406 // as soon as the service is started.
407 UpdateNameOwnerAndBlock();
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900408
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900409 return success;
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900410}
411
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900412bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name,
413 const std::string& signal_name,
414 SignalCallback signal_callback) {
415 bus_->AssertOnDBusThread();
416
417 if (!ConnectToNameOwnerChangedSignal())
418 return false;
419
420 const std::string absolute_signal_name =
armansitof4364642014-09-06 02:49:34 +0900421 GetAbsoluteMemberName(interface_name, signal_name);
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900422
423 // Add a match rule so the signal goes through HandleMessage().
424 const std::string match_rule =
425 base::StringPrintf("type='signal', interface='%s', path='%s'",
426 interface_name.c_str(),
427 object_path_.value().c_str());
428 return AddMatchRuleWithCallback(match_rule,
429 absolute_signal_name,
430 signal_callback);
431}
432
433void ObjectProxy::WaitForServiceToBeAvailableInternal() {
434 bus_->AssertOnDBusThread();
435
436 if (!ConnectToNameOwnerChangedSignal()) { // Failed to connect to the signal.
437 const bool service_is_ready = false;
438 bus_->GetOriginTaskRunner()->PostTask(
439 FROM_HERE,
440 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
441 this, service_is_ready));
442 return;
443 }
444
445 const bool service_is_available = !service_name_owner_.empty();
446 if (service_is_available) { // Service is already available.
447 bus_->GetOriginTaskRunner()->PostTask(
448 FROM_HERE,
449 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
450 this, service_is_available));
451 return;
452 }
453}
454
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900455DBusHandlerResult ObjectProxy::HandleMessage(
456 DBusConnection* connection,
457 DBusMessage* raw_message) {
458 bus_->AssertOnDBusThread();
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900459
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900460 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
461 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
462
463 // raw_message will be unrefed on exit of the function. Increment the
464 // reference so we can use it in Signal.
465 dbus_message_ref(raw_message);
466 scoped_ptr<Signal> signal(
467 Signal::FromRawMessage(raw_message));
468
keybuk@chromium.orgb929d752012-03-01 13:01:05 +0900469 // Verify the signal comes from the object we're proxying for, this is
470 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
471 // allow other object proxies to handle instead.
thestig@chromium.org56057f22013-05-05 00:48:37 +0900472 const ObjectPath path = signal->GetPath();
keybuk@chromium.orgb929d752012-03-01 13:01:05 +0900473 if (path != object_path_) {
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +0900474 if (path.value() == kDBusSystemObjectPath &&
thestig@chromium.org56057f22013-05-05 00:48:37 +0900475 signal->GetMember() == kNameOwnerChangedMember) {
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900476 // Handle NameOwnerChanged separately
haruki@chromium.orgc8d231a2012-11-14 20:02:59 +0900477 return HandleNameOwnerChanged(signal.Pass());
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900478 }
keybuk@chromium.orgb929d752012-03-01 13:01:05 +0900479 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
480 }
481
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900482 const std::string interface = signal->GetInterface();
483 const std::string member = signal->GetMember();
484
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +0900485 statistics::AddReceivedSignal(service_name_, interface, member);
486
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900487 // Check if we know about the signal.
armansitof4364642014-09-06 02:49:34 +0900488 const std::string absolute_signal_name = GetAbsoluteMemberName(
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900489 interface, member);
490 MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
491 if (iter == method_table_.end()) {
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900492 // Don't know about the signal.
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900493 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
494 }
satorux@chromium.org63c284f2011-10-15 07:37:12 +0900495 VLOG(1) << "Signal received: " << signal->ToString();
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900496
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900497 std::string sender = signal->GetSender();
498 if (service_name_owner_ != sender) {
499 LOG(ERROR) << "Rejecting a message from a wrong sender.";
500 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
501 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
502 }
503
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900504 const base::TimeTicks start_time = base::TimeTicks::Now();
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900505 if (bus_->HasDBusThread()) {
506 // Post a task to run the method in the origin thread.
507 // Transfer the ownership of |signal| to RunMethod().
508 // |released_signal| will be deleted in RunMethod().
509 Signal* released_signal = signal.release();
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900510 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
511 base::Bind(&ObjectProxy::RunMethod,
512 this,
513 start_time,
514 iter->second,
515 released_signal));
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900516 } else {
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900517 const base::TimeTicks start_time = base::TimeTicks::Now();
518 // If the D-Bus thread is not used, just call the callback on the
519 // current thread. Transfer the ownership of |signal| to RunMethod().
520 Signal* released_signal = signal.release();
521 RunMethod(start_time, iter->second, released_signal);
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900522 }
523
hashimoto@chromium.orgfb3930a2013-12-17 17:41:57 +0900524 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
525 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
526 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900527}
528
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900529void ObjectProxy::RunMethod(base::TimeTicks start_time,
keybuk@chromium.org2594a712013-04-24 09:12:35 +0900530 std::vector<SignalCallback> signal_callbacks,
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900531 Signal* signal) {
532 bus_->AssertOnOriginThread();
533
keybuk@chromium.org2594a712013-04-24 09:12:35 +0900534 for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin();
535 iter != signal_callbacks.end(); ++iter)
536 iter->Run(signal);
537
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900538 // Delete the message on the D-Bus thread. See comments in
539 // RunResponseCallback().
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900540 bus_->GetDBusTaskRunner()->PostTask(
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900541 FROM_HERE,
thestig@chromium.org56057f22013-05-05 00:48:37 +0900542 base::Bind(&base::DeletePointer<Signal>, signal));
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900543
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900544 // Record time spent for handling the signal.
545 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
546 base::TimeTicks::Now() - start_time);
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900547}
548
549DBusHandlerResult ObjectProxy::HandleMessageThunk(
550 DBusConnection* connection,
551 DBusMessage* raw_message,
552 void* user_data) {
553 ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
554 return self->HandleMessage(connection, raw_message);
555}
556
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900557void ObjectProxy::LogMethodCallFailure(
satorux@chromium.org31bb21e2012-05-31 15:12:11 +0900558 const base::StringPiece& interface_name,
559 const base::StringPiece& method_name,
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900560 const base::StringPiece& error_name,
561 const base::StringPiece& error_message) const {
stevenjb@chromium.orgc415c482014-08-09 06:57:19 +0900562 if (ignore_service_unknown_errors_ &&
563 (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900564 return;
stevenjb@chromium.orgc415c482014-08-09 06:57:19 +0900565 logging::LogSeverity severity = logging::LOG_ERROR;
566 // "UnknownObject" indicates that an object or service is no longer available,
567 // e.g. a Shill network service has gone out of range. Treat these as warnings
568 // not errors.
569 if (error_name == kErrorObjectUnknown)
570 severity = logging::LOG_WARNING;
571 std::ostringstream msg;
572 msg << "Failed to call method: " << interface_name << "." << method_name
573 << ": object_path= " << object_path_.value()
574 << ": " << error_name << ": " << error_message;
575 logging::LogAtLevel(severity, msg.str());
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900576}
577
satorux@chromium.org31bb21e2012-05-31 15:12:11 +0900578void ObjectProxy::OnCallMethodError(const std::string& interface_name,
579 const std::string& method_name,
580 ResponseCallback response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900581 ErrorResponse* error_response) {
582 if (error_response) {
583 // Error message may contain the error message as string.
thestig@chromium.org56057f22013-05-05 00:48:37 +0900584 MessageReader reader(error_response);
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900585 std::string error_message;
586 reader.PopString(&error_message);
satorux@chromium.org31bb21e2012-05-31 15:12:11 +0900587 LogMethodCallFailure(interface_name,
588 method_name,
589 error_response->GetErrorName(),
590 error_message);
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900591 }
592 response_callback.Run(NULL);
593}
594
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900595bool ObjectProxy::AddMatchRuleWithCallback(
596 const std::string& match_rule,
597 const std::string& absolute_signal_name,
598 SignalCallback signal_callback) {
599 DCHECK(!match_rule.empty());
600 DCHECK(!absolute_signal_name.empty());
601 bus_->AssertOnDBusThread();
602
603 if (match_rules_.find(match_rule) == match_rules_.end()) {
604 ScopedDBusError error;
605 bus_->AddMatch(match_rule, error.get());
606 if (error.is_set()) {
thestig@chromium.org56057f22013-05-05 00:48:37 +0900607 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
608 << error.name() << ": " << error.message();
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900609 return false;
610 } else {
611 // Store the match rule, so that we can remove this in Detach().
612 match_rules_.insert(match_rule);
613 // Add the signal callback to the method table.
keybuk@chromium.org2594a712013-04-24 09:12:35 +0900614 method_table_[absolute_signal_name].push_back(signal_callback);
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900615 return true;
616 }
617 } else {
618 // We already have the match rule.
keybuk@chromium.org2594a712013-04-24 09:12:35 +0900619 method_table_[absolute_signal_name].push_back(signal_callback);
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900620 return true;
621 }
622}
623
624bool ObjectProxy::AddMatchRuleWithoutCallback(
625 const std::string& match_rule,
626 const std::string& absolute_signal_name) {
627 DCHECK(!match_rule.empty());
628 DCHECK(!absolute_signal_name.empty());
629 bus_->AssertOnDBusThread();
630
631 if (match_rules_.find(match_rule) != match_rules_.end())
632 return true;
633
634 ScopedDBusError error;
635 bus_->AddMatch(match_rule, error.get());
636 if (error.is_set()) {
thestig@chromium.org56057f22013-05-05 00:48:37 +0900637 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
638 << error.name() << ": " << error.message();
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900639 return false;
640 }
641 // Store the match rule, so that we can remove this in Detach().
642 match_rules_.insert(match_rule);
643 return true;
644}
645
646void ObjectProxy::UpdateNameOwnerAndBlock() {
647 bus_->AssertOnDBusThread();
satorux@chromium.org9b1f85d2013-08-16 18:16:42 +0900648 // Errors should be suppressed here, as the service may not be yet running
649 // when connecting to signals of the service, which is just fine.
650 // The ObjectProxy will be notified when the service is launched via
651 // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
thestig@chromium.org56057f22013-05-05 00:48:37 +0900652 service_name_owner_ =
satorux@chromium.org9b1f85d2013-08-16 18:16:42 +0900653 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900654}
655
haruki@chromium.orgc8d231a2012-11-14 20:02:59 +0900656DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
657 scoped_ptr<Signal> signal) {
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900658 DCHECK(signal);
659 bus_->AssertOnDBusThread();
660
661 // Confirm the validity of the NameOwnerChanged signal.
thestig@chromium.org56057f22013-05-05 00:48:37 +0900662 if (signal->GetMember() == kNameOwnerChangedMember &&
663 signal->GetInterface() == kDBusSystemObjectInterface &&
664 signal->GetSender() == kDBusSystemObjectAddress) {
haruki@chromium.orgc8d231a2012-11-14 20:02:59 +0900665 MessageReader reader(signal.get());
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900666 std::string name, old_owner, new_owner;
667 if (reader.PopString(&name) &&
668 reader.PopString(&old_owner) &&
669 reader.PopString(&new_owner) &&
670 name == service_name_) {
671 service_name_owner_ = new_owner;
hashimoto@chromium.org4f3851c2013-09-27 16:12:03 +0900672 bus_->GetOriginTaskRunner()->PostTask(
673 FROM_HERE,
674 base::Bind(&ObjectProxy::RunNameOwnerChangedCallback,
675 this, old_owner, new_owner));
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900676
677 const bool service_is_available = !service_name_owner_.empty();
678 if (service_is_available) {
679 bus_->GetOriginTaskRunner()->PostTask(
680 FROM_HERE,
681 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
682 this, service_is_available));
683 }
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900684 }
685 }
686
keybuk@chromium.org359c9b62012-11-27 09:23:25 +0900687 // Always return unhandled to let other object proxies handle the same
688 // signal.
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900689 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
690}
691
hashimoto@chromium.org4f3851c2013-09-27 16:12:03 +0900692void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
693 const std::string& new_owner) {
694 bus_->AssertOnOriginThread();
695 if (!name_owner_changed_callback_.is_null())
696 name_owner_changed_callback_.Run(old_owner, new_owner);
697}
698
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900699void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
700 bool service_is_available) {
701 bus_->AssertOnOriginThread();
702
703 std::vector<WaitForServiceToBeAvailableCallback> callbacks;
704 callbacks.swap(wait_for_service_to_be_available_callbacks_);
705 for (size_t i = 0; i < callbacks.size(); ++i)
706 callbacks[i].Run(service_is_available);
707}
708
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900709} // namespace dbus