blob: 5d9d8e842f0a43b2aad95c778d4c8141f47bf0fc [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
dcheng6c1ffcf2015-12-28 11:24:50 +09005#include "dbus/object_proxy.h"
satorux@chromium.org163f1cb2011-08-18 05:58:12 +09006
avi0ad0ce02015-12-23 03:12:45 +09007#include <stddef.h>
dcheng6c1ffcf2015-12-28 11:24:50 +09008#include <utility>
avi0ad0ce02015-12-23 03:12:45 +09009
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090010#include "base/bind.h"
11#include "base/logging.h"
avi@chromium.orga29af562013-07-18 08:00:30 +090012#include "base/message_loop/message_loop.h"
satorux@chromium.org5a92cf32011-09-07 05:53:30 +090013#include "base/metrics/histogram.h"
tfarina@chromium.org0eed10b2013-04-18 06:42:40 +090014#include "base/strings/string_piece.h"
avi@chromium.orgffcdb952013-06-11 16:27:01 +090015#include "base/strings/stringprintf.h"
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +090016#include "base/task_runner_util.h"
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090017#include "base/threading/thread.h"
18#include "base/threading/thread_restrictions.h"
dcheng6c1ffcf2015-12-28 11:24:50 +090019#include "dbus/bus.h"
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +090020#include "dbus/dbus_statistics.h"
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090021#include "dbus/message.h"
keybuk@google.combf4649a2012-02-15 06:29:06 +090022#include "dbus/object_path.h"
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090023#include "dbus/scoped_dbus_error.h"
armansitof4364642014-09-06 02:49:34 +090024#include "dbus/util.h"
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090025
thestig@chromium.org56057f22013-05-05 00:48:37 +090026namespace dbus {
27
satorux@chromium.org7f0c4512011-08-23 16:29:21 +090028namespace {
29
adamk@chromium.org35c0eef2012-02-11 06:45:23 +090030const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown";
stevenjb@chromium.orgc415c482014-08-09 06:57:19 +090031const char kErrorObjectUnknown[] = "org.freedesktop.DBus.Error.UnknownObject";
adamk@chromium.org35c0eef2012-02-11 06:45:23 +090032
satorux@chromium.org5a92cf32011-09-07 05:53:30 +090033// Used for success ratio histograms. 1 for success, 0 for failure.
34const int kSuccessRatioHistogramMaxValue = 2;
35
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +090036// The path of D-Bus Object sending NameOwnerChanged signal.
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +090037const char kDBusSystemObjectPath[] = "/org/freedesktop/DBus";
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +090038
thestig@chromium.org56057f22013-05-05 00:48:37 +090039// The D-Bus Object interface.
40const char kDBusSystemObjectInterface[] = "org.freedesktop.DBus";
41
42// The D-Bus Object address.
43const char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";
44
45// The NameOwnerChanged member in |kDBusSystemObjectInterface|.
46const char kNameOwnerChangedMember[] = "NameOwnerChanged";
47
satorux@chromium.orgb1753152011-11-11 17:36:22 +090048// An empty function used for ObjectProxy::EmptyResponseCallback().
thestig@chromium.org56057f22013-05-05 00:48:37 +090049void EmptyResponseCallbackBody(Response* /*response*/) {
satorux@chromium.orgb1753152011-11-11 17:36:22 +090050}
51
satorux@chromium.org7f0c4512011-08-23 16:29:21 +090052} // namespace
53
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090054ObjectProxy::ObjectProxy(Bus* bus,
55 const std::string& service_name,
keybuk@google.combf4649a2012-02-15 06:29:06 +090056 const ObjectPath& object_path,
adamk@chromium.org35c0eef2012-02-11 06:45:23 +090057 int options)
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090058 : bus_(bus),
59 service_name_(service_name),
satorux@chromium.org7f0c4512011-08-23 16:29:21 +090060 object_path_(object_path),
adamk@chromium.org35c0eef2012-02-11 06:45:23 +090061 ignore_service_unknown_errors_(
62 options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090063}
64
65ObjectProxy::~ObjectProxy() {
hashimoto14eb1502015-03-30 16:01:39 +090066 DCHECK(pending_calls_.empty());
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090067}
68
69// Originally we tried to make |method_call| a const reference, but we
70// gave up as dbus_connection_send_with_reply_and_block() takes a
71// non-const pointer of DBusMessage as the second parameter.
dcheng30c5a172016-04-09 07:55:04 +090072std::unique_ptr<Response> ObjectProxy::CallMethodAndBlockWithErrorDetails(
73 MethodCall* method_call,
74 int timeout_ms,
75 ScopedDBusError* error) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090076 bus_->AssertOnDBusThread();
77
hashimoto@chromium.orgb0305512012-05-23 15:55:22 +090078 if (!bus_->Connect() ||
79 !method_call->SetDestination(service_name_) ||
80 !method_call->SetPath(object_path_))
dcheng30c5a172016-04-09 07:55:04 +090081 return std::unique_ptr<Response>();
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090082
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090083 DBusMessage* request_message = method_call->raw_message();
84
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090085 // Send the message synchronously.
satorux@chromium.org5a92cf32011-09-07 05:53:30 +090086 const base::TimeTicks start_time = base::TimeTicks::Now();
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090087 DBusMessage* response_message =
avakulenko1d8962b2014-09-17 10:44:09 +090088 bus_->SendWithReplyAndBlock(request_message, timeout_ms, error->get());
satorux@chromium.org5a92cf32011-09-07 05:53:30 +090089 // Record if the method call is successful, or not. 1 if successful.
90 UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
91 response_message ? 1 : 0,
92 kSuccessRatioHistogramMaxValue);
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +090093 statistics::AddBlockingSentMethodCall(service_name_,
94 method_call->GetInterface(),
95 method_call->GetMember());
satorux@chromium.org163f1cb2011-08-18 05:58:12 +090096
97 if (!response_message) {
satorux@chromium.org31bb21e2012-05-31 15:12:11 +090098 LogMethodCallFailure(method_call->GetInterface(),
99 method_call->GetMember(),
avakulenko1d8962b2014-09-17 10:44:09 +0900100 error->is_set() ? error->name() : "unknown error type",
101 error->is_set() ? error->message() : "");
dcheng30c5a172016-04-09 07:55:04 +0900102 return std::unique_ptr<Response>();
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900103 }
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900104 // Record time spent for the method call. Don't include failures.
105 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
106 base::TimeTicks::Now() - start_time);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900107
satorux@chromium.orgffa83a92011-08-24 12:32:06 +0900108 return Response::FromRawMessage(response_message);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900109}
110
dcheng30c5a172016-04-09 07:55:04 +0900111std::unique_ptr<Response> ObjectProxy::CallMethodAndBlock(
112 MethodCall* method_call,
113 int timeout_ms) {
avakulenko1d8962b2014-09-17 10:44:09 +0900114 ScopedDBusError error;
115 return CallMethodAndBlockWithErrorDetails(method_call, timeout_ms, &error);
116}
117
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900118void ObjectProxy::CallMethod(MethodCall* method_call,
119 int timeout_ms,
120 ResponseCallback callback) {
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900121 CallMethodWithErrorCallback(method_call, timeout_ms, callback,
122 base::Bind(&ObjectProxy::OnCallMethodError,
123 this,
satorux@chromium.org31bb21e2012-05-31 15:12:11 +0900124 method_call->GetInterface(),
125 method_call->GetMember(),
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900126 callback));
127}
128
129void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
130 int timeout_ms,
131 ResponseCallback callback,
132 ErrorCallback error_callback) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900133 bus_->AssertOnOriginThread();
134
hashimoto@chromium.orgb0305512012-05-23 15:55:22 +0900135 const base::TimeTicks start_time = base::TimeTicks::Now();
136
137 if (!method_call->SetDestination(service_name_) ||
138 !method_call->SetPath(object_path_)) {
139 // In case of a failure, run the error callback with NULL.
140 DBusMessage* response_message = NULL;
141 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
142 this,
143 callback,
144 error_callback,
145 start_time,
146 response_message);
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900147 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
hashimoto@chromium.orgb0305512012-05-23 15:55:22 +0900148 return;
149 }
150
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900151 // Increment the reference count so we can safely reference the
152 // underlying request message until the method call is complete. This
153 // will be unref'ed in StartAsyncMethodCall().
154 DBusMessage* request_message = method_call->raw_message();
155 dbus_message_ref(request_message);
156
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900157 base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall,
158 this,
159 timeout_ms,
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900160 request_message,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900161 callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900162 error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900163 start_time);
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +0900164 statistics::AddSentMethodCall(service_name_,
165 method_call->GetInterface(),
166 method_call->GetMember());
167
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900168 // Wait for the response in the D-Bus thread.
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900169 bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900170}
171
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900172void ObjectProxy::ConnectToSignal(const std::string& interface_name,
173 const std::string& signal_name,
174 SignalCallback signal_callback,
175 OnConnectedCallback on_connected_callback) {
176 bus_->AssertOnOriginThread();
177
dtapuskad998f172015-01-23 23:41:21 +0900178 if (bus_->HasDBusThread()) {
179 base::PostTaskAndReplyWithResult(
180 bus_->GetDBusTaskRunner(), FROM_HERE,
181 base::Bind(&ObjectProxy::ConnectToSignalInternal, this, interface_name,
182 signal_name, signal_callback),
183 base::Bind(on_connected_callback, interface_name, signal_name));
184 } else {
185 // If the bus doesn't have a dedicated dbus thread we need to call
186 // ConnectToSignalInternal directly otherwise we might miss a signal
187 // that is currently queued if we do a PostTask.
188 const bool success =
189 ConnectToSignalInternal(interface_name, signal_name, signal_callback);
190 on_connected_callback.Run(interface_name, signal_name, success);
191 }
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900192}
193
hashimoto@chromium.org4f3851c2013-09-27 16:12:03 +0900194void ObjectProxy::SetNameOwnerChangedCallback(
195 NameOwnerChangedCallback callback) {
196 bus_->AssertOnOriginThread();
197
198 name_owner_changed_callback_ = callback;
199}
200
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900201void ObjectProxy::WaitForServiceToBeAvailable(
202 WaitForServiceToBeAvailableCallback callback) {
203 bus_->AssertOnOriginThread();
204
205 wait_for_service_to_be_available_callbacks_.push_back(callback);
206 bus_->GetDBusTaskRunner()->PostTask(
207 FROM_HERE,
208 base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal, this));
209}
210
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900211void ObjectProxy::Detach() {
212 bus_->AssertOnDBusThread();
213
hashimoto46be6e92014-12-04 16:41:55 +0900214 if (bus_->is_connected())
215 bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this);
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900216
hashimoto14eb1502015-03-30 16:01:39 +0900217 for (const auto& match_rule : match_rules_) {
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900218 ScopedDBusError error;
hashimoto14eb1502015-03-30 16:01:39 +0900219 bus_->RemoveMatch(match_rule, error.get());
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900220 if (error.is_set()) {
221 // There is nothing we can do to recover, so just print the error.
hashimoto14eb1502015-03-30 16:01:39 +0900222 LOG(ERROR) << "Failed to remove match rule: " << match_rule;
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900223 }
224 }
satorux@chromium.org5b3e4962011-11-24 07:08:38 +0900225 match_rules_.clear();
hashimoto14eb1502015-03-30 16:01:39 +0900226
227 for (auto* pending_call : pending_calls_) {
228 dbus_pending_call_cancel(pending_call);
229 dbus_pending_call_unref(pending_call);
230 }
231 pending_calls_.clear();
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900232}
233
satorux@chromium.orgb1753152011-11-11 17:36:22 +0900234// static
235ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() {
236 return base::Bind(&EmptyResponseCallbackBody);
237}
238
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900239ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
240 ObjectProxy* in_object_proxy,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900241 ResponseCallback in_response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900242 ErrorCallback in_error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900243 base::TimeTicks in_start_time)
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900244 : object_proxy(in_object_proxy),
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900245 response_callback(in_response_callback),
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900246 error_callback(in_error_callback),
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900247 start_time(in_start_time) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900248}
249
250ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
251}
252
253void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900254 DBusMessage* request_message,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900255 ResponseCallback response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900256 ErrorCallback error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900257 base::TimeTicks start_time) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900258 bus_->AssertOnDBusThread();
259
260 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900261 // In case of a failure, run the error callback with NULL.
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900262 DBusMessage* response_message = NULL;
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900263 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
264 this,
265 response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900266 error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900267 start_time,
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900268 response_message);
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900269 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900270
271 dbus_message_unref(request_message);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900272 return;
273 }
274
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900275 DBusPendingCall* pending_call = NULL;
276
277 bus_->SendWithReply(request_message, &pending_call, timeout_ms);
278
279 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
280 // The data will be deleted in OnPendingCallIsCompleteThunk().
281 OnPendingCallIsCompleteData* data =
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900282 new OnPendingCallIsCompleteData(this, response_callback, error_callback,
283 start_time);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900284
285 // This returns false only when unable to allocate memory.
286 const bool success = dbus_pending_call_set_notify(
287 pending_call,
288 &ObjectProxy::OnPendingCallIsCompleteThunk,
289 data,
hashimotob6084f52015-03-30 15:52:21 +0900290 &DeleteVoidPointer<OnPendingCallIsCompleteData>);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900291 CHECK(success) << "Unable to allocate memory";
hashimoto14eb1502015-03-30 16:01:39 +0900292 pending_calls_.insert(pending_call);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900293
294 // It's now safe to unref the request message.
295 dbus_message_unref(request_message);
296}
297
298void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900299 ResponseCallback response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900300 ErrorCallback error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900301 base::TimeTicks start_time) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900302 bus_->AssertOnDBusThread();
303
304 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900305 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
306 this,
307 response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900308 error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900309 start_time,
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900310 response_message);
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900311 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
hashimoto14eb1502015-03-30 16:01:39 +0900312
313 // Remove the pending call from the set.
314 pending_calls_.erase(pending_call);
315 dbus_pending_call_unref(pending_call);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900316}
317
318void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900319 ErrorCallback error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900320 base::TimeTicks start_time,
satorux@chromium.org47d706b2011-10-04 22:47:21 +0900321 DBusMessage* response_message) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900322 bus_->AssertOnOriginThread();
323
satorux@chromium.orgb1753152011-11-11 17:36:22 +0900324 bool method_call_successful = false;
satorux@chromium.orgffa83a92011-08-24 12:32:06 +0900325 if (!response_message) {
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900326 // The response is not received.
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900327 error_callback.Run(NULL);
satorux@chromium.orgffa83a92011-08-24 12:32:06 +0900328 } else if (dbus_message_get_type(response_message) ==
329 DBUS_MESSAGE_TYPE_ERROR) {
330 // This will take |response_message| and release (unref) it.
dcheng30c5a172016-04-09 07:55:04 +0900331 std::unique_ptr<ErrorResponse> error_response(
thestig@chromium.org56057f22013-05-05 00:48:37 +0900332 ErrorResponse::FromRawMessage(response_message));
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900333 error_callback.Run(error_response.get());
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900334 // Delete the message on the D-Bus thread. See below for why.
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900335 bus_->GetDBusTaskRunner()->PostTask(
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900336 FROM_HERE,
thestig@chromium.org56057f22013-05-05 00:48:37 +0900337 base::Bind(&base::DeletePointer<ErrorResponse>,
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900338 error_response.release()));
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900339 } else {
satorux@chromium.orgffa83a92011-08-24 12:32:06 +0900340 // This will take |response_message| and release (unref) it.
dcheng30c5a172016-04-09 07:55:04 +0900341 std::unique_ptr<Response> response(
342 Response::FromRawMessage(response_message));
satorux@chromium.orgc6ac7572011-09-01 03:02:43 +0900343 // The response is successfully received.
satorux@chromium.orgffa83a92011-08-24 12:32:06 +0900344 response_callback.Run(response.get());
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900345 // The message should be deleted on the D-Bus thread for a complicated
346 // reason:
347 //
348 // libdbus keeps track of the number of bytes in the incoming message
349 // queue to ensure that the data size in the queue is manageable. The
350 // bookkeeping is partly done via dbus_message_unref(), and immediately
351 // asks the client code (Chrome) to stop monitoring the underlying
352 // socket, if the number of bytes exceeds a certian number, which is set
353 // to 63MB, per dbus-transport.cc:
354 //
355 // /* Try to default to something that won't totally hose the system,
356 // * but doesn't impose too much of a limitation.
357 // */
358 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
359 //
360 // The monitoring of the socket is done on the D-Bus thread (see Watch
361 // class in bus.cc), hence we should stop the monitoring from D-Bus
362 // thread, not from the current thread here, which is likely UI thread.
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900363 bus_->GetDBusTaskRunner()->PostTask(
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900364 FROM_HERE,
thestig@chromium.org56057f22013-05-05 00:48:37 +0900365 base::Bind(&base::DeletePointer<Response>, response.release()));
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900366
satorux@chromium.orgb1753152011-11-11 17:36:22 +0900367 method_call_successful = true;
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900368 // Record time spent for the method call. Don't include failures.
369 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
370 base::TimeTicks::Now() - start_time);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900371 }
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900372 // Record if the method call is successful, or not. 1 if successful.
373 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
satorux@chromium.orgb1753152011-11-11 17:36:22 +0900374 method_call_successful,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900375 kSuccessRatioHistogramMaxValue);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900376}
377
378void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call,
379 void* user_data) {
380 OnPendingCallIsCompleteData* data =
381 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data);
382 ObjectProxy* self = data->object_proxy;
383 self->OnPendingCallIsComplete(pending_call,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900384 data->response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900385 data->error_callback,
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900386 data->start_time);
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900387}
388
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900389bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900390 bus_->AssertOnDBusThread();
391
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900392 if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
393 return false;
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900394
hashimoto46be6e92014-12-04 16:41:55 +0900395 bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this);
396
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900397 // Add a match_rule listening NameOwnerChanged for the well-known name
398 // |service_name_|.
399 const std::string name_owner_changed_match_rule =
400 base::StringPrintf(
401 "type='signal',interface='org.freedesktop.DBus',"
402 "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
403 "sender='org.freedesktop.DBus',arg0='%s'",
404 service_name_.c_str());
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900405
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900406 const bool success =
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900407 AddMatchRuleWithoutCallback(name_owner_changed_match_rule,
408 "org.freedesktop.DBus.NameOwnerChanged");
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900409
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900410 // Try getting the current name owner. It's not guaranteed that we can get
411 // the name owner at this moment, as the service may not yet be started. If
412 // that's the case, we'll get the name owner via NameOwnerChanged signal,
413 // as soon as the service is started.
414 UpdateNameOwnerAndBlock();
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900415
hashimoto@chromium.orgce5c6152013-09-26 15:40:04 +0900416 return success;
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900417}
418
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900419bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name,
420 const std::string& signal_name,
421 SignalCallback signal_callback) {
422 bus_->AssertOnDBusThread();
423
424 if (!ConnectToNameOwnerChangedSignal())
425 return false;
426
427 const std::string absolute_signal_name =
armansitof4364642014-09-06 02:49:34 +0900428 GetAbsoluteMemberName(interface_name, signal_name);
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900429
430 // Add a match rule so the signal goes through HandleMessage().
431 const std::string match_rule =
432 base::StringPrintf("type='signal', interface='%s', path='%s'",
433 interface_name.c_str(),
434 object_path_.value().c_str());
435 return AddMatchRuleWithCallback(match_rule,
436 absolute_signal_name,
437 signal_callback);
438}
439
440void ObjectProxy::WaitForServiceToBeAvailableInternal() {
441 bus_->AssertOnDBusThread();
442
443 if (!ConnectToNameOwnerChangedSignal()) { // Failed to connect to the signal.
444 const bool service_is_ready = false;
445 bus_->GetOriginTaskRunner()->PostTask(
446 FROM_HERE,
447 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
448 this, service_is_ready));
449 return;
450 }
451
452 const bool service_is_available = !service_name_owner_.empty();
453 if (service_is_available) { // Service is already available.
454 bus_->GetOriginTaskRunner()->PostTask(
455 FROM_HERE,
456 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
457 this, service_is_available));
458 return;
459 }
460}
461
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900462DBusHandlerResult ObjectProxy::HandleMessage(
463 DBusConnection* connection,
464 DBusMessage* raw_message) {
465 bus_->AssertOnDBusThread();
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900466
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900467 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
468 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
469
470 // raw_message will be unrefed on exit of the function. Increment the
471 // reference so we can use it in Signal.
472 dbus_message_ref(raw_message);
dcheng30c5a172016-04-09 07:55:04 +0900473 std::unique_ptr<Signal> signal(Signal::FromRawMessage(raw_message));
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900474
keybuk@chromium.orgb929d752012-03-01 13:01:05 +0900475 // Verify the signal comes from the object we're proxying for, this is
476 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
477 // allow other object proxies to handle instead.
thestig@chromium.org56057f22013-05-05 00:48:37 +0900478 const ObjectPath path = signal->GetPath();
keybuk@chromium.orgb929d752012-03-01 13:01:05 +0900479 if (path != object_path_) {
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +0900480 if (path.value() == kDBusSystemObjectPath &&
thestig@chromium.org56057f22013-05-05 00:48:37 +0900481 signal->GetMember() == kNameOwnerChangedMember) {
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900482 // Handle NameOwnerChanged separately
dcheng6c1ffcf2015-12-28 11:24:50 +0900483 return HandleNameOwnerChanged(std::move(signal));
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900484 }
keybuk@chromium.orgb929d752012-03-01 13:01:05 +0900485 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
486 }
487
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900488 const std::string interface = signal->GetInterface();
489 const std::string member = signal->GetMember();
490
stevenjb@chromium.org3199bd12012-11-15 06:03:29 +0900491 statistics::AddReceivedSignal(service_name_, interface, member);
492
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900493 // Check if we know about the signal.
armansitof4364642014-09-06 02:49:34 +0900494 const std::string absolute_signal_name = GetAbsoluteMemberName(
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900495 interface, member);
496 MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
497 if (iter == method_table_.end()) {
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900498 // Don't know about the signal.
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900499 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
500 }
satorux@chromium.org63c284f2011-10-15 07:37:12 +0900501 VLOG(1) << "Signal received: " << signal->ToString();
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900502
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900503 std::string sender = signal->GetSender();
504 if (service_name_owner_ != sender) {
505 LOG(ERROR) << "Rejecting a message from a wrong sender.";
506 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
507 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
508 }
509
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900510 const base::TimeTicks start_time = base::TimeTicks::Now();
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900511 if (bus_->HasDBusThread()) {
512 // Post a task to run the method in the origin thread.
513 // Transfer the ownership of |signal| to RunMethod().
514 // |released_signal| will be deleted in RunMethod().
515 Signal* released_signal = signal.release();
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900516 bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
517 base::Bind(&ObjectProxy::RunMethod,
518 this,
519 start_time,
520 iter->second,
521 released_signal));
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900522 } else {
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900523 const base::TimeTicks start_time = base::TimeTicks::Now();
524 // If the D-Bus thread is not used, just call the callback on the
525 // current thread. Transfer the ownership of |signal| to RunMethod().
526 Signal* released_signal = signal.release();
527 RunMethod(start_time, iter->second, released_signal);
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900528 }
529
hashimoto@chromium.orgfb3930a2013-12-17 17:41:57 +0900530 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
531 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
532 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900533}
534
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900535void ObjectProxy::RunMethod(base::TimeTicks start_time,
keybuk@chromium.org2594a712013-04-24 09:12:35 +0900536 std::vector<SignalCallback> signal_callbacks,
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900537 Signal* signal) {
538 bus_->AssertOnOriginThread();
539
keybuk@chromium.org2594a712013-04-24 09:12:35 +0900540 for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin();
541 iter != signal_callbacks.end(); ++iter)
542 iter->Run(signal);
543
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900544 // Delete the message on the D-Bus thread. See comments in
545 // RunResponseCallback().
hashimoto@chromium.org955f6482013-09-26 13:32:29 +0900546 bus_->GetDBusTaskRunner()->PostTask(
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900547 FROM_HERE,
thestig@chromium.org56057f22013-05-05 00:48:37 +0900548 base::Bind(&base::DeletePointer<Signal>, signal));
satorux@chromium.org9f10a6e2012-06-02 11:53:20 +0900549
satorux@chromium.org5a92cf32011-09-07 05:53:30 +0900550 // Record time spent for handling the signal.
551 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
552 base::TimeTicks::Now() - start_time);
satorux@chromium.org7f0c4512011-08-23 16:29:21 +0900553}
554
555DBusHandlerResult ObjectProxy::HandleMessageThunk(
556 DBusConnection* connection,
557 DBusMessage* raw_message,
558 void* user_data) {
559 ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
560 return self->HandleMessage(connection, raw_message);
561}
562
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900563void ObjectProxy::LogMethodCallFailure(
satorux@chromium.org31bb21e2012-05-31 15:12:11 +0900564 const base::StringPiece& interface_name,
565 const base::StringPiece& method_name,
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900566 const base::StringPiece& error_name,
567 const base::StringPiece& error_message) const {
stevenjb@chromium.orgc415c482014-08-09 06:57:19 +0900568 if (ignore_service_unknown_errors_ &&
569 (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900570 return;
jbroman5dc27f92016-01-22 13:49:25 +0900571
stevenjb@chromium.orgc415c482014-08-09 06:57:19 +0900572 std::ostringstream msg;
573 msg << "Failed to call method: " << interface_name << "." << method_name
574 << ": object_path= " << object_path_.value()
575 << ": " << error_name << ": " << error_message;
jbroman5dc27f92016-01-22 13:49:25 +0900576
577 // "UnknownObject" indicates that an object or service is no longer available,
578 // e.g. a Shill network service has gone out of range. Treat these as warnings
579 // not errors.
580 if (error_name == kErrorObjectUnknown)
581 LOG(WARNING) << msg.str();
582 else
583 LOG(ERROR) << msg.str();
adamk@chromium.org35c0eef2012-02-11 06:45:23 +0900584}
585
satorux@chromium.org31bb21e2012-05-31 15:12:11 +0900586void ObjectProxy::OnCallMethodError(const std::string& interface_name,
587 const std::string& method_name,
588 ResponseCallback response_callback,
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900589 ErrorResponse* error_response) {
590 if (error_response) {
591 // Error message may contain the error message as string.
thestig@chromium.org56057f22013-05-05 00:48:37 +0900592 MessageReader reader(error_response);
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900593 std::string error_message;
594 reader.PopString(&error_message);
satorux@chromium.org31bb21e2012-05-31 15:12:11 +0900595 LogMethodCallFailure(interface_name,
596 method_name,
597 error_response->GetErrorName(),
598 error_message);
hashimoto@chromium.org0d2477e2012-04-20 12:18:27 +0900599 }
600 response_callback.Run(NULL);
601}
602
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900603bool ObjectProxy::AddMatchRuleWithCallback(
604 const std::string& match_rule,
605 const std::string& absolute_signal_name,
606 SignalCallback signal_callback) {
607 DCHECK(!match_rule.empty());
608 DCHECK(!absolute_signal_name.empty());
609 bus_->AssertOnDBusThread();
610
611 if (match_rules_.find(match_rule) == match_rules_.end()) {
612 ScopedDBusError error;
613 bus_->AddMatch(match_rule, error.get());
614 if (error.is_set()) {
thestig@chromium.org56057f22013-05-05 00:48:37 +0900615 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
616 << error.name() << ": " << error.message();
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900617 return false;
618 } else {
619 // Store the match rule, so that we can remove this in Detach().
620 match_rules_.insert(match_rule);
621 // Add the signal callback to the method table.
keybuk@chromium.org2594a712013-04-24 09:12:35 +0900622 method_table_[absolute_signal_name].push_back(signal_callback);
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900623 return true;
624 }
625 } else {
626 // We already have the match rule.
keybuk@chromium.org2594a712013-04-24 09:12:35 +0900627 method_table_[absolute_signal_name].push_back(signal_callback);
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900628 return true;
629 }
630}
631
632bool ObjectProxy::AddMatchRuleWithoutCallback(
633 const std::string& match_rule,
634 const std::string& absolute_signal_name) {
635 DCHECK(!match_rule.empty());
636 DCHECK(!absolute_signal_name.empty());
637 bus_->AssertOnDBusThread();
638
639 if (match_rules_.find(match_rule) != match_rules_.end())
640 return true;
641
642 ScopedDBusError error;
643 bus_->AddMatch(match_rule, error.get());
644 if (error.is_set()) {
thestig@chromium.org56057f22013-05-05 00:48:37 +0900645 LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
646 << error.name() << ": " << error.message();
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900647 return false;
648 }
649 // Store the match rule, so that we can remove this in Detach().
650 match_rules_.insert(match_rule);
651 return true;
652}
653
654void ObjectProxy::UpdateNameOwnerAndBlock() {
655 bus_->AssertOnDBusThread();
satorux@chromium.org9b1f85d2013-08-16 18:16:42 +0900656 // Errors should be suppressed here, as the service may not be yet running
657 // when connecting to signals of the service, which is just fine.
658 // The ObjectProxy will be notified when the service is launched via
659 // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
thestig@chromium.org56057f22013-05-05 00:48:37 +0900660 service_name_owner_ =
satorux@chromium.org9b1f85d2013-08-16 18:16:42 +0900661 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900662}
663
haruki@chromium.orgc8d231a2012-11-14 20:02:59 +0900664DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
dcheng30c5a172016-04-09 07:55:04 +0900665 std::unique_ptr<Signal> signal) {
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900666 DCHECK(signal);
667 bus_->AssertOnDBusThread();
668
669 // Confirm the validity of the NameOwnerChanged signal.
thestig@chromium.org56057f22013-05-05 00:48:37 +0900670 if (signal->GetMember() == kNameOwnerChangedMember &&
671 signal->GetInterface() == kDBusSystemObjectInterface &&
672 signal->GetSender() == kDBusSystemObjectAddress) {
haruki@chromium.orgc8d231a2012-11-14 20:02:59 +0900673 MessageReader reader(signal.get());
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900674 std::string name, old_owner, new_owner;
675 if (reader.PopString(&name) &&
676 reader.PopString(&old_owner) &&
677 reader.PopString(&new_owner) &&
678 name == service_name_) {
679 service_name_owner_ = new_owner;
hashimoto@chromium.org4f3851c2013-09-27 16:12:03 +0900680 bus_->GetOriginTaskRunner()->PostTask(
681 FROM_HERE,
682 base::Bind(&ObjectProxy::RunNameOwnerChangedCallback,
683 this, old_owner, new_owner));
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900684
685 const bool service_is_available = !service_name_owner_.empty();
686 if (service_is_available) {
687 bus_->GetOriginTaskRunner()->PostTask(
688 FROM_HERE,
689 base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
690 this, service_is_available));
691 }
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900692 }
693 }
694
keybuk@chromium.org359c9b62012-11-27 09:23:25 +0900695 // Always return unhandled to let other object proxies handle the same
696 // signal.
haruki@chromium.orgc5623ec2012-10-29 15:27:33 +0900697 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
698}
699
hashimoto@chromium.org4f3851c2013-09-27 16:12:03 +0900700void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
701 const std::string& new_owner) {
702 bus_->AssertOnOriginThread();
703 if (!name_owner_changed_callback_.is_null())
704 name_owner_changed_callback_.Run(old_owner, new_owner);
705}
706
hashimoto@chromium.orged268092013-10-02 16:53:09 +0900707void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
708 bool service_is_available) {
709 bus_->AssertOnOriginThread();
710
711 std::vector<WaitForServiceToBeAvailableCallback> callbacks;
712 callbacks.swap(wait_for_service_to_be_available_callbacks_);
713 for (size_t i = 0; i < callbacks.size(); ++i)
714 callbacks[i].Run(service_is_available);
715}
716
satorux@chromium.org163f1cb2011-08-18 05:58:12 +0900717} // namespace dbus