ash: Add launcher overflow bubble.
[chromium-blink-merge.git] / dbus / object_proxy.cc
blobba51efaf61ac0305eea09dd55d788010feea049f
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "dbus/bus.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop.h"
10 #include "base/metrics/histogram.h"
11 #include "base/string_piece.h"
12 #include "base/stringprintf.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/thread_restrictions.h"
15 #include "dbus/message.h"
16 #include "dbus/object_path.h"
17 #include "dbus/object_proxy.h"
18 #include "dbus/scoped_dbus_error.h"
20 namespace {
22 const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown";
24 // Used for success ratio histograms. 1 for success, 0 for failure.
25 const int kSuccessRatioHistogramMaxValue = 2;
27 // Gets the absolute signal name by concatenating the interface name and
28 // the signal name. Used for building keys for method_table_ in
29 // ObjectProxy.
30 std::string GetAbsoluteSignalName(
31 const std::string& interface_name,
32 const std::string& signal_name) {
33 return interface_name + "." + signal_name;
36 // An empty function used for ObjectProxy::EmptyResponseCallback().
37 void EmptyResponseCallbackBody(dbus::Response* unused_response) {
40 } // namespace
42 namespace dbus {
44 ObjectProxy::ObjectProxy(Bus* bus,
45 const std::string& service_name,
46 const ObjectPath& object_path,
47 int options)
48 : bus_(bus),
49 service_name_(service_name),
50 object_path_(object_path),
51 filter_added_(false),
52 ignore_service_unknown_errors_(
53 options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
56 ObjectProxy::~ObjectProxy() {
59 // Originally we tried to make |method_call| a const reference, but we
60 // gave up as dbus_connection_send_with_reply_and_block() takes a
61 // non-const pointer of DBusMessage as the second parameter.
62 Response* ObjectProxy::CallMethodAndBlock(MethodCall* method_call,
63 int timeout_ms) {
64 bus_->AssertOnDBusThread();
66 if (!bus_->Connect() ||
67 !method_call->SetDestination(service_name_) ||
68 !method_call->SetPath(object_path_))
69 return NULL;
71 DBusMessage* request_message = method_call->raw_message();
73 ScopedDBusError error;
75 // Send the message synchronously.
76 const base::TimeTicks start_time = base::TimeTicks::Now();
77 DBusMessage* response_message =
78 bus_->SendWithReplyAndBlock(request_message, timeout_ms, error.get());
79 // Record if the method call is successful, or not. 1 if successful.
80 UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
81 response_message ? 1 : 0,
82 kSuccessRatioHistogramMaxValue);
84 if (!response_message) {
85 LogMethodCallFailure(method_call->GetInterface(),
86 method_call->GetMember(),
87 error.is_set() ? error.name() : "unknown error type",
88 error.is_set() ? error.message() : "");
89 return NULL;
91 // Record time spent for the method call. Don't include failures.
92 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
93 base::TimeTicks::Now() - start_time);
95 return Response::FromRawMessage(response_message);
98 void ObjectProxy::CallMethod(MethodCall* method_call,
99 int timeout_ms,
100 ResponseCallback callback) {
101 CallMethodWithErrorCallback(method_call, timeout_ms, callback,
102 base::Bind(&ObjectProxy::OnCallMethodError,
103 this,
104 method_call->GetInterface(),
105 method_call->GetMember(),
106 callback));
109 void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
110 int timeout_ms,
111 ResponseCallback callback,
112 ErrorCallback error_callback) {
113 bus_->AssertOnOriginThread();
115 const base::TimeTicks start_time = base::TimeTicks::Now();
117 if (!method_call->SetDestination(service_name_) ||
118 !method_call->SetPath(object_path_)) {
119 // In case of a failure, run the error callback with NULL.
120 DBusMessage* response_message = NULL;
121 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
122 this,
123 callback,
124 error_callback,
125 start_time,
126 response_message);
127 bus_->PostTaskToOriginThread(FROM_HERE, task);
128 return;
131 // Increment the reference count so we can safely reference the
132 // underlying request message until the method call is complete. This
133 // will be unref'ed in StartAsyncMethodCall().
134 DBusMessage* request_message = method_call->raw_message();
135 dbus_message_ref(request_message);
137 base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall,
138 this,
139 timeout_ms,
140 request_message,
141 callback,
142 error_callback,
143 start_time);
144 // Wait for the response in the D-Bus thread.
145 bus_->PostTaskToDBusThread(FROM_HERE, task);
148 void ObjectProxy::ConnectToSignal(const std::string& interface_name,
149 const std::string& signal_name,
150 SignalCallback signal_callback,
151 OnConnectedCallback on_connected_callback) {
152 bus_->AssertOnOriginThread();
154 bus_->PostTaskToDBusThread(FROM_HERE,
155 base::Bind(&ObjectProxy::ConnectToSignalInternal,
156 this,
157 interface_name,
158 signal_name,
159 signal_callback,
160 on_connected_callback));
163 void ObjectProxy::Detach() {
164 bus_->AssertOnDBusThread();
166 if (filter_added_) {
167 if (!bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this)) {
168 LOG(ERROR) << "Failed to remove filter function";
172 for (std::set<std::string>::iterator iter = match_rules_.begin();
173 iter != match_rules_.end(); ++iter) {
174 ScopedDBusError error;
175 bus_->RemoveMatch(*iter, error.get());
176 if (error.is_set()) {
177 // There is nothing we can do to recover, so just print the error.
178 LOG(ERROR) << "Failed to remove match rule: " << *iter;
181 match_rules_.clear();
184 // static
185 ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() {
186 return base::Bind(&EmptyResponseCallbackBody);
189 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
190 ObjectProxy* in_object_proxy,
191 ResponseCallback in_response_callback,
192 ErrorCallback in_error_callback,
193 base::TimeTicks in_start_time)
194 : object_proxy(in_object_proxy),
195 response_callback(in_response_callback),
196 error_callback(in_error_callback),
197 start_time(in_start_time) {
200 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
203 void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
204 DBusMessage* request_message,
205 ResponseCallback response_callback,
206 ErrorCallback error_callback,
207 base::TimeTicks start_time) {
208 bus_->AssertOnDBusThread();
210 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
211 // In case of a failure, run the error callback with NULL.
212 DBusMessage* response_message = NULL;
213 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
214 this,
215 response_callback,
216 error_callback,
217 start_time,
218 response_message);
219 bus_->PostTaskToOriginThread(FROM_HERE, task);
221 dbus_message_unref(request_message);
222 return;
225 DBusPendingCall* pending_call = NULL;
227 bus_->SendWithReply(request_message, &pending_call, timeout_ms);
229 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
230 // The data will be deleted in OnPendingCallIsCompleteThunk().
231 OnPendingCallIsCompleteData* data =
232 new OnPendingCallIsCompleteData(this, response_callback, error_callback,
233 start_time);
235 // This returns false only when unable to allocate memory.
236 const bool success = dbus_pending_call_set_notify(
237 pending_call,
238 &ObjectProxy::OnPendingCallIsCompleteThunk,
239 data,
240 NULL);
241 CHECK(success) << "Unable to allocate memory";
242 dbus_pending_call_unref(pending_call);
244 // It's now safe to unref the request message.
245 dbus_message_unref(request_message);
248 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
249 ResponseCallback response_callback,
250 ErrorCallback error_callback,
251 base::TimeTicks start_time) {
252 bus_->AssertOnDBusThread();
254 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
255 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
256 this,
257 response_callback,
258 error_callback,
259 start_time,
260 response_message);
261 bus_->PostTaskToOriginThread(FROM_HERE, task);
264 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
265 ErrorCallback error_callback,
266 base::TimeTicks start_time,
267 DBusMessage* response_message) {
268 bus_->AssertOnOriginThread();
270 bool method_call_successful = false;
271 if (!response_message) {
272 // The response is not received.
273 error_callback.Run(NULL);
274 } else if (dbus_message_get_type(response_message) ==
275 DBUS_MESSAGE_TYPE_ERROR) {
276 // This will take |response_message| and release (unref) it.
277 scoped_ptr<dbus::ErrorResponse> error_response(
278 dbus::ErrorResponse::FromRawMessage(response_message));
279 error_callback.Run(error_response.get());
280 // Delete the message on the D-Bus thread. See below for why.
281 bus_->PostTaskToDBusThread(
282 FROM_HERE,
283 base::Bind(&base::DeletePointer<dbus::ErrorResponse>,
284 error_response.release()));
285 } else {
286 // This will take |response_message| and release (unref) it.
287 scoped_ptr<dbus::Response> response(
288 dbus::Response::FromRawMessage(response_message));
289 // The response is successfully received.
290 response_callback.Run(response.get());
291 // The message should be deleted on the D-Bus thread for a complicated
292 // reason:
294 // libdbus keeps track of the number of bytes in the incoming message
295 // queue to ensure that the data size in the queue is manageable. The
296 // bookkeeping is partly done via dbus_message_unref(), and immediately
297 // asks the client code (Chrome) to stop monitoring the underlying
298 // socket, if the number of bytes exceeds a certian number, which is set
299 // to 63MB, per dbus-transport.cc:
301 // /* Try to default to something that won't totally hose the system,
302 // * but doesn't impose too much of a limitation.
303 // */
304 // transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
306 // The monitoring of the socket is done on the D-Bus thread (see Watch
307 // class in bus.cc), hence we should stop the monitoring from D-Bus
308 // thread, not from the current thread here, which is likely UI thread.
309 bus_->PostTaskToDBusThread(
310 FROM_HERE,
311 base::Bind(&base::DeletePointer<dbus::Response>,
312 response.release()));
314 method_call_successful = true;
315 // Record time spent for the method call. Don't include failures.
316 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
317 base::TimeTicks::Now() - start_time);
319 // Record if the method call is successful, or not. 1 if successful.
320 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
321 method_call_successful,
322 kSuccessRatioHistogramMaxValue);
325 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call,
326 void* user_data) {
327 OnPendingCallIsCompleteData* data =
328 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data);
329 ObjectProxy* self = data->object_proxy;
330 self->OnPendingCallIsComplete(pending_call,
331 data->response_callback,
332 data->error_callback,
333 data->start_time);
334 delete data;
337 void ObjectProxy::ConnectToSignalInternal(
338 const std::string& interface_name,
339 const std::string& signal_name,
340 SignalCallback signal_callback,
341 OnConnectedCallback on_connected_callback) {
342 bus_->AssertOnDBusThread();
344 const std::string absolute_signal_name =
345 GetAbsoluteSignalName(interface_name, signal_name);
347 // Will become true, if everything is successful.
348 bool success = false;
350 if (bus_->Connect() && bus_->SetUpAsyncOperations()) {
351 // We should add the filter only once. Otherwise, HandleMessage() will
352 // be called more than once.
353 if (!filter_added_) {
354 if (bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this)) {
355 filter_added_ = true;
356 } else {
357 LOG(ERROR) << "Failed to add filter function";
360 // Add a match rule so the signal goes through HandleMessage().
361 const std::string match_rule =
362 base::StringPrintf("type='signal', interface='%s', path='%s'",
363 interface_name.c_str(),
364 object_path_.value().c_str());
366 // Add the match rule if we don't have it.
367 if (match_rules_.find(match_rule) == match_rules_.end()) {
368 ScopedDBusError error;
369 bus_->AddMatch(match_rule, error.get());;
370 if (error.is_set()) {
371 LOG(ERROR) << "Failed to add match rule: " << match_rule;
372 } else {
373 // Store the match rule, so that we can remove this in Detach().
374 match_rules_.insert(match_rule);
375 // Add the signal callback to the method table.
376 method_table_[absolute_signal_name] = signal_callback;
377 success = true;
379 } else {
380 // We already have the match rule.
381 method_table_[absolute_signal_name] = signal_callback;
382 success = true;
386 // Run on_connected_callback in the origin thread.
387 bus_->PostTaskToOriginThread(
388 FROM_HERE,
389 base::Bind(&ObjectProxy::OnConnected,
390 this,
391 on_connected_callback,
392 interface_name,
393 signal_name,
394 success));
397 void ObjectProxy::OnConnected(OnConnectedCallback on_connected_callback,
398 const std::string& interface_name,
399 const std::string& signal_name,
400 bool success) {
401 bus_->AssertOnOriginThread();
403 on_connected_callback.Run(interface_name, signal_name, success);
406 DBusHandlerResult ObjectProxy::HandleMessage(
407 DBusConnection* connection,
408 DBusMessage* raw_message) {
409 bus_->AssertOnDBusThread();
410 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
411 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
413 // raw_message will be unrefed on exit of the function. Increment the
414 // reference so we can use it in Signal.
415 dbus_message_ref(raw_message);
416 scoped_ptr<Signal> signal(
417 Signal::FromRawMessage(raw_message));
419 // Verify the signal comes from the object we're proxying for, this is
420 // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
421 // allow other object proxies to handle instead.
422 const dbus::ObjectPath path = signal->GetPath();
423 if (path != object_path_) {
424 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
427 const std::string interface = signal->GetInterface();
428 const std::string member = signal->GetMember();
430 // Check if we know about the signal.
431 const std::string absolute_signal_name = GetAbsoluteSignalName(
432 interface, member);
433 MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
434 if (iter == method_table_.end()) {
435 // Don't know about the signal.
436 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
438 VLOG(1) << "Signal received: " << signal->ToString();
440 const base::TimeTicks start_time = base::TimeTicks::Now();
441 if (bus_->HasDBusThread()) {
442 // Post a task to run the method in the origin thread.
443 // Transfer the ownership of |signal| to RunMethod().
444 // |released_signal| will be deleted in RunMethod().
445 Signal* released_signal = signal.release();
446 bus_->PostTaskToOriginThread(FROM_HERE,
447 base::Bind(&ObjectProxy::RunMethod,
448 this,
449 start_time,
450 iter->second,
451 released_signal));
452 } else {
453 const base::TimeTicks start_time = base::TimeTicks::Now();
454 // If the D-Bus thread is not used, just call the callback on the
455 // current thread. Transfer the ownership of |signal| to RunMethod().
456 Signal* released_signal = signal.release();
457 RunMethod(start_time, iter->second, released_signal);
460 return DBUS_HANDLER_RESULT_HANDLED;
463 void ObjectProxy::RunMethod(base::TimeTicks start_time,
464 SignalCallback signal_callback,
465 Signal* signal) {
466 bus_->AssertOnOriginThread();
468 signal_callback.Run(signal);
469 // Delete the message on the D-Bus thread. See comments in
470 // RunResponseCallback().
471 bus_->PostTaskToDBusThread(
472 FROM_HERE,
473 base::Bind(&base::DeletePointer<dbus::Signal>, signal));
475 // Record time spent for handling the signal.
476 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
477 base::TimeTicks::Now() - start_time);
480 DBusHandlerResult ObjectProxy::HandleMessageThunk(
481 DBusConnection* connection,
482 DBusMessage* raw_message,
483 void* user_data) {
484 ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
485 return self->HandleMessage(connection, raw_message);
488 void ObjectProxy::LogMethodCallFailure(
489 const base::StringPiece& interface_name,
490 const base::StringPiece& method_name,
491 const base::StringPiece& error_name,
492 const base::StringPiece& error_message) const {
493 if (ignore_service_unknown_errors_ && error_name == kErrorServiceUnknown)
494 return;
495 LOG(ERROR) << "Failed to call method: "
496 << interface_name << "." << method_name
497 << ": object_path= " << object_path_.value()
498 << ": " << error_name << ": " << error_message;
501 void ObjectProxy::OnCallMethodError(const std::string& interface_name,
502 const std::string& method_name,
503 ResponseCallback response_callback,
504 ErrorResponse* error_response) {
505 if (error_response) {
506 // Error message may contain the error message as string.
507 dbus::MessageReader reader(error_response);
508 std::string error_message;
509 reader.PopString(&error_message);
510 LogMethodCallFailure(interface_name,
511 method_name,
512 error_response->GetErrorName(),
513 error_message);
515 response_callback.Run(NULL);
518 } // namespace dbus