Fix for Geolocation webTCT failures
[platform/framework/web/chromium-efl.git] / dbus / object_proxy.cc
1 // Copyright 2012 The Chromium Authors
2 // 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/object_proxy.h"
6
7 #include <stddef.h>
8 #include <utility>
9
10 #include "base/containers/contains.h"
11 #include "base/debug/alias.h"
12 #include "base/debug/leak_annotations.h"
13 #include "base/functional/bind.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/logging.h"
16 #include "base/strings/string_piece.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/task/sequenced_task_runner.h"
19 #include "base/threading/scoped_blocking_call.h"
20 #include "base/threading/thread.h"
21 #include "base/threading/thread_restrictions.h"
22 #include "dbus/bus.h"
23 #include "dbus/dbus_statistics.h"
24 #include "dbus/error.h"
25 #include "dbus/message.h"
26 #include "dbus/object_path.h"
27 #include "dbus/scoped_dbus_error.h"
28 #include "dbus/util.h"
29
30 namespace dbus {
31
32 namespace {
33
34 constexpr char kErrorServiceUnknown[] =
35     "org.freedesktop.DBus.Error.ServiceUnknown";
36 constexpr char kErrorObjectUnknown[] =
37     "org.freedesktop.DBus.Error.UnknownObject";
38
39 // The path of D-Bus Object sending NameOwnerChanged signal.
40 constexpr char kDBusSystemObjectPath[] = "/org/freedesktop/DBus";
41
42 // The D-Bus Object interface.
43 constexpr char kDBusSystemObjectInterface[] = "org.freedesktop.DBus";
44
45 // The D-Bus Object address.
46 constexpr char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";
47
48 // The NameOwnerChanged member in |kDBusSystemObjectInterface|.
49 constexpr char kNameOwnerChangedMember[] = "NameOwnerChanged";
50
51 }  // namespace
52
53 ObjectProxy::ReplyCallbackHolder::ReplyCallbackHolder(
54     scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
55     ResponseOrErrorCallback callback)
56     : origin_task_runner_(std::move(origin_task_runner)),
57       callback_(std::move(callback)) {
58   DCHECK(origin_task_runner_.get());
59   DCHECK(!callback_.is_null());
60 }
61
62 ObjectProxy::ReplyCallbackHolder::ReplyCallbackHolder(
63     ReplyCallbackHolder&& other) = default;
64
65 ObjectProxy::ReplyCallbackHolder::~ReplyCallbackHolder() {
66   if (callback_.is_null()) {
67     // This is the regular case.
68     // CallMethod and its family creates this object on the origin thread,
69     // PostTask()s to the D-Bus thread for actual D-Bus communication,
70     // then PostTask()s back to the origin thread to invoke the |callback_|.
71     // At that timing, the ownership of callback should be released via
72     // ReleaseCallback().
73     // Otherwise, this instance was moved to another one. Do nothing in
74     // either case.
75     return;
76   }
77
78   // The only case where |origin_task_runner_| becomes nullptr is that
79   // this is moved. In such a case, |callback_| should be nullptr, too, so it
80   // should be handled above. Thus, here |origin_task_runner_| must not be
81   // nullptr.
82   DCHECK(origin_task_runner_.get());
83
84   if (origin_task_runner_->RunsTasksInCurrentSequence()) {
85     // Destroyed on the origin thread. This happens when PostTask()ing to
86     // the D-Bus thread fails. The |callback_| can be destroyed on the
87     // current thread safely. Do nothing here, and let member destruction
88     // destroy the callback.
89     return;
90   }
91
92   // Here is on D-Bus thread, so try to PostTask() to destroy the callback.
93   // to the origin thread.
94   // The |origin_task_runner_| may already have stopped. E.g., on Chrome's
95   // shutdown the message loop of the UI thread (= the origin thread) stops
96   // before D-Bus threaed's. In such a case, PostTask() fails. Because we
97   // cannot do much thing here, instead, simply leak the callback rather than
98   // destroying it on the D-Bus thread, which could be unexpected from the
99   // direct or indirect caller of CallMethod.
100   auto* callback_to_be_deleted =
101       new ResponseOrErrorCallback(std::move(callback_));
102   ANNOTATE_LEAKING_OBJECT_PTR(callback_to_be_deleted);
103   origin_task_runner_->PostTask(
104       FROM_HERE, base::BindOnce(&base::DeletePointer<ResponseOrErrorCallback>,
105                                 callback_to_be_deleted));
106 }
107
108 ObjectProxy::ResponseOrErrorCallback
109 ObjectProxy::ReplyCallbackHolder::ReleaseCallback() {
110   DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
111   return std::move(callback_);
112 }
113
114 ObjectProxy::ObjectProxy(Bus* bus,
115                          const std::string& service_name,
116                          const ObjectPath& object_path,
117                          int options)
118     : bus_(bus),
119       service_name_(service_name),
120       object_path_(object_path),
121       ignore_service_unknown_errors_(options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
122   LOG_IF(FATAL, !object_path_.IsValid()) << object_path_.value();
123 }
124
125 ObjectProxy::~ObjectProxy() {
126   DCHECK(pending_calls_.empty());
127 }
128
129 // Originally we tried to make |method_call| a const reference, but we
130 // gave up as dbus_connection_send_with_reply_and_block() takes a
131 // non-const pointer of DBusMessage as the second parameter.
132 base::expected<std::unique_ptr<Response>, Error>
133 ObjectProxy::CallMethodAndBlock(MethodCall* method_call, int timeout_ms) {
134   bus_->AssertOnDBusThread();
135
136   if (!bus_->Connect() || !method_call->SetDestination(service_name_) ||
137       !method_call->SetPath(object_path_)) {
138     // Not an error from libdbus, so returns invalid error.
139     return base::unexpected(Error());
140   }
141
142   // Send the message synchronously.
143   auto result =
144       bus_->SendWithReplyAndBlock(method_call->raw_message(), timeout_ms);
145   statistics::AddBlockingSentMethodCall(
146       service_name_, method_call->GetInterface(), method_call->GetMember());
147   if (!result.has_value()) {
148     LogMethodCallFailure(method_call->GetInterface(), method_call->GetMember(),
149                          result.error().name(), result.error().message());
150   }
151   return result;
152 }
153
154 void ObjectProxy::CallMethod(MethodCall* method_call,
155                              int timeout_ms,
156                              ResponseCallback callback) {
157   auto internal_callback = base::BindOnce(
158       &ObjectProxy::OnCallMethod, this, method_call->GetInterface(),
159       method_call->GetMember(), std::move(callback));
160
161   CallMethodWithErrorResponse(method_call, timeout_ms,
162                               std::move(internal_callback));
163 }
164
165 void ObjectProxy::CallMethodWithErrorResponse(
166     MethodCall* method_call,
167     int timeout_ms,
168     ResponseOrErrorCallback callback) {
169   bus_->AssertOnOriginThread();
170
171   ReplyCallbackHolder callback_holder(bus_->GetOriginTaskRunner(),
172                                       std::move(callback));
173
174   if (!method_call->SetDestination(service_name_) ||
175       !method_call->SetPath(object_path_)) {
176     // In case of a failure, run the error callback with nullptr.
177     base::OnceClosure task =
178         base::BindOnce(&ObjectProxy::RunResponseOrErrorCallback, this,
179                        std::move(callback_holder), nullptr /* response */,
180                        nullptr /* error_response */);
181     bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, std::move(task));
182     return;
183   }
184
185   // Increment the reference count so we can safely reference the
186   // underlying request message until the method call is complete. This
187   // will be unref'ed in StartAsyncMethodCall().
188   DBusMessage* request_message = method_call->raw_message();
189   dbus_message_ref(request_message);
190
191   statistics::AddSentMethodCall(service_name_, method_call->GetInterface(),
192                                 method_call->GetMember());
193
194   // Wait for the response in the D-Bus thread.
195   base::OnceClosure task =
196       base::BindOnce(&ObjectProxy::StartAsyncMethodCall, this, timeout_ms,
197                      request_message, std::move(callback_holder));
198   bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, std::move(task));
199 }
200
201 void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
202                                               int timeout_ms,
203                                               ResponseCallback callback,
204                                               ErrorCallback error_callback) {
205   auto internal_callback = base::BindOnce(
206       [](ResponseCallback callback, ErrorCallback error_callback,
207          Response* response, ErrorResponse* error_response) {
208         if (response) {
209           std::move(callback).Run(response);
210         } else {
211           std::move(error_callback).Run(error_response);
212         }
213       },
214       std::move(callback), std::move(error_callback));
215
216   CallMethodWithErrorResponse(method_call, timeout_ms,
217                               std::move(internal_callback));
218 }
219
220 void ObjectProxy::ConnectToSignal(const std::string& interface_name,
221                                   const std::string& signal_name,
222                                   SignalCallback signal_callback,
223                                   OnConnectedCallback on_connected_callback) {
224   bus_->AssertOnOriginThread();
225
226   if (bus_->HasDBusThread()) {
227     bus_->GetDBusTaskRunner()->PostTaskAndReplyWithResult(
228         FROM_HERE,
229         base::BindOnce(&ObjectProxy::ConnectToSignalAndBlock, this,
230                        interface_name, signal_name, signal_callback),
231         base::BindOnce(std::move(on_connected_callback), interface_name,
232                        signal_name));
233   } else {
234     // If the bus doesn't have a dedicated dbus thread we need to call
235     // ConnectToSignalAndBlock directly otherwise we might miss a signal
236     // that is currently queued if we do a PostTask.
237     const bool success =
238         ConnectToSignalAndBlock(interface_name, signal_name, signal_callback);
239     std::move(on_connected_callback).Run(interface_name, signal_name, success);
240   }
241 }
242
243 bool ObjectProxy::ConnectToSignalAndBlock(const std::string& interface_name,
244                                           const std::string& signal_name,
245                                           SignalCallback signal_callback) {
246   bus_->AssertOnDBusThread();
247
248   if (!ConnectToNameOwnerChangedSignal())
249     return false;
250
251   const std::string absolute_signal_name =
252       GetAbsoluteMemberName(interface_name, signal_name);
253
254   // Add a match rule so the signal goes through HandleMessage().
255   const std::string match_rule = base::StringPrintf(
256       "type='signal', sender='%s', interface='%s', path='%s'",
257       service_name_.c_str(), interface_name.c_str(),
258       object_path_.value().c_str());
259   return AddMatchRuleWithCallback(match_rule, absolute_signal_name,
260                                   signal_callback);
261 }
262
263 void ObjectProxy::SetNameOwnerChangedCallback(
264     NameOwnerChangedCallback callback) {
265   bus_->AssertOnOriginThread();
266
267   name_owner_changed_callback_ = callback;
268
269   bus_->GetDBusTaskRunner()->PostTask(
270       FROM_HERE,
271       base::BindOnce(&ObjectProxy::TryConnectToNameOwnerChangedSignal, this));
272 }
273
274 void ObjectProxy::WaitForServiceToBeAvailable(
275     WaitForServiceToBeAvailableCallback callback) {
276   bus_->AssertOnOriginThread();
277
278   wait_for_service_to_be_available_callbacks_.push_back(std::move(callback));
279   bus_->GetDBusTaskRunner()->PostTask(
280       FROM_HERE,
281       base::BindOnce(&ObjectProxy::WaitForServiceToBeAvailableInternal, this));
282 }
283
284 void ObjectProxy::Detach() {
285   bus_->AssertOnDBusThread();
286
287   if (bus_->IsConnected())
288     bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this);
289
290   for (const auto& match_rule : match_rules_) {
291     Error error;
292     bus_->RemoveMatch(match_rule, &error);
293     if (error.IsValid()) {
294       // There is nothing we can do to recover, so just print the error.
295       LOG(ERROR) << "Failed to remove match rule: " << match_rule;
296     }
297   }
298   match_rules_.clear();
299
300   for (auto* pending_call : pending_calls_) {
301     base::ScopedBlockingCall scoped_blocking_call(
302         FROM_HERE, base::BlockingType::MAY_BLOCK);
303
304     dbus_pending_call_cancel(pending_call);
305     dbus_pending_call_unref(pending_call);
306   }
307   pending_calls_.clear();
308 }
309
310 void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
311                                        DBusMessage* request_message,
312                                        ReplyCallbackHolder callback_holder) {
313   bus_->AssertOnDBusThread();
314   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
315                                                 base::BlockingType::MAY_BLOCK);
316
317   if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
318     // In case of a failure, run the error callback with nullptr.
319     base::OnceClosure task =
320         base::BindOnce(&ObjectProxy::RunResponseOrErrorCallback, this,
321                        std::move(callback_holder), nullptr /* response */,
322                        nullptr /* error_response */);
323     bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, std::move(task));
324
325     dbus_message_unref(request_message);
326     return;
327   }
328
329   DBusPendingCall* dbus_pending_call = nullptr;
330   bus_->SendWithReply(request_message, &dbus_pending_call, timeout_ms);
331
332   using PendingCallback =
333       base::OnceCallback<void(DBusPendingCall * pending_call)>;
334   // This returns false only when unable to allocate memory.
335   const bool success = dbus_pending_call_set_notify(
336       dbus_pending_call,
337       [](DBusPendingCall* pending_call, void* user_data) {
338         std::move(*static_cast<PendingCallback*>(user_data)).Run(pending_call);
339       },
340       // PendingCallback instance is owned by libdbus.
341       new PendingCallback(base::BindOnce(&ObjectProxy::OnPendingCallIsComplete,
342                                          this, std::move(callback_holder))),
343       [](void* user_data) { delete static_cast<PendingCallback*>(user_data); });
344   CHECK(success) << "Unable to allocate memory";
345   pending_calls_.insert(dbus_pending_call);
346
347   // It's now safe to unref the request message.
348   dbus_message_unref(request_message);
349 }
350
351 void ObjectProxy::OnPendingCallIsComplete(ReplyCallbackHolder callback_holder,
352                                           DBusPendingCall* pending_call) {
353   bus_->AssertOnDBusThread();
354   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
355                                                 base::BlockingType::MAY_BLOCK);
356
357   DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
358
359   // Either |response| or |error_response| takes ownership of the
360   // |response_message|.
361   std::unique_ptr<Response> response;
362   std::unique_ptr<ErrorResponse> error_response;
363   if (dbus_message_get_type(response_message) == DBUS_MESSAGE_TYPE_ERROR) {
364     error_response = ErrorResponse::FromRawMessage(response_message);
365   } else {
366     response = Response::FromRawMessage(response_message);
367   }
368
369   base::OnceClosure task = base::BindOnce(
370       &ObjectProxy::RunResponseOrErrorCallback, this,
371       std::move(callback_holder), response.get(), error_response.get());
372
373   // The message should be deleted on the D-Bus thread for a complicated
374   // reason:
375   //
376   // libdbus keeps track of the number of bytes in the incoming message
377   // queue to ensure that the data size in the queue is manageable. The
378   // bookkeeping is partly done via dbus_message_unref(), and immediately
379   // asks the client code (Chrome) to stop monitoring the underlying
380   // socket, if the number of bytes exceeds a certian number, which is set
381   // to 63MB, per dbus-transport.cc:
382   //
383   //   /* Try to default to something that won't totally hose the system,
384   //    * but doesn't impose too much of a limitation.
385   //    */
386   //   transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
387   //
388   // The monitoring of the socket is done on the D-Bus thread (see Watch
389   // class in bus.cc), hence we should stop the monitoring on D-Bus thread.
390   bus_->GetOriginTaskRunner()->PostTaskAndReply(
391       FROM_HERE, std::move(task),
392       base::BindOnce(
393           [](Response* response, ErrorResponse* error_response) {
394             // Do nothing.
395           },
396           base::Owned(response.release()),
397           base::Owned(error_response.release())));
398
399   // Remove the pending call from the set.
400   pending_calls_.erase(pending_call);
401   dbus_pending_call_unref(pending_call);
402 }
403
404 void ObjectProxy::RunResponseOrErrorCallback(
405     ReplyCallbackHolder callback_holder,
406     Response* response,
407     ErrorResponse* error_response) {
408   bus_->AssertOnOriginThread();
409   callback_holder.ReleaseCallback().Run(response, error_response);
410 }
411
412 bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
413   bus_->AssertOnDBusThread();
414
415   if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
416     return false;
417
418   bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this);
419
420   // Add a match_rule listening NameOwnerChanged for the well-known name
421   // |service_name_|.
422   const std::string name_owner_changed_match_rule = base::StringPrintf(
423       "type='signal',interface='org.freedesktop.DBus',"
424       "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
425       "sender='org.freedesktop.DBus',arg0='%s'",
426       service_name_.c_str());
427
428   const bool success = AddMatchRuleWithoutCallback(
429       name_owner_changed_match_rule, "org.freedesktop.DBus.NameOwnerChanged");
430
431   // Try getting the current name owner. It's not guaranteed that we can get
432   // the name owner at this moment, as the service may not yet be started. If
433   // that's the case, we'll get the name owner via NameOwnerChanged signal,
434   // as soon as the service is started.
435   UpdateNameOwnerAndBlock();
436
437   return success;
438 }
439
440 void ObjectProxy::TryConnectToNameOwnerChangedSignal() {
441   bus_->AssertOnDBusThread();
442
443   bool success = ConnectToNameOwnerChangedSignal();
444   LOG_IF(WARNING, !success)
445       << "Failed to connect to NameOwnerChanged signal for object: "
446       << object_path_.value();
447 }
448
449 void ObjectProxy::WaitForServiceToBeAvailableInternal() {
450   bus_->AssertOnDBusThread();
451
452   if (!ConnectToNameOwnerChangedSignal()) {  // Failed to connect to the signal.
453     const bool service_is_ready = false;
454     bus_->GetOriginTaskRunner()->PostTask(
455         FROM_HERE,
456         base::BindOnce(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
457                        this, service_is_ready));
458     return;
459   }
460
461   const bool service_is_available = !service_name_owner_.empty();
462   if (service_is_available) {  // Service is already available.
463     bus_->GetOriginTaskRunner()->PostTask(
464         FROM_HERE,
465         base::BindOnce(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
466                        this, service_is_available));
467     return;
468   }
469 }
470
471 DBusHandlerResult ObjectProxy::HandleMessage(DBusConnection* connection,
472                                              DBusMessage* raw_message) {
473   bus_->AssertOnDBusThread();
474
475   if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
476     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
477
478   // raw_message will be unrefed on exit of the function. Increment the
479   // reference so we can use it in Signal.
480   dbus_message_ref(raw_message);
481   std::unique_ptr<Signal> signal(Signal::FromRawMessage(raw_message));
482
483   // Verify the signal comes from the object we're proxying for, this is
484   // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
485   // allow other object proxies to handle instead.
486   const ObjectPath path = signal->GetPath();
487   if (path != object_path_) {
488     if (path.value() == kDBusSystemObjectPath &&
489         signal->GetMember() == kNameOwnerChangedMember) {
490       // Handle NameOwnerChanged separately
491       return HandleNameOwnerChanged(std::move(signal));
492     }
493     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
494   }
495
496   std::string sender = signal->GetSender();
497   // Ignore message from sender we are not interested in.
498   if (service_name_owner_ != sender)
499     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
500
501   const std::string interface = signal->GetInterface();
502   const std::string member = signal->GetMember();
503
504   statistics::AddReceivedSignal(service_name_, interface, member);
505
506   // Check if we know about the signal.
507   const std::string absolute_signal_name =
508       GetAbsoluteMemberName(interface, member);
509   MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
510   if (iter == method_table_.end()) {
511     // Don't know about the signal.
512     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
513   }
514   VLOG(1) << "Signal received: " << signal->ToString();
515
516   if (bus_->HasDBusThread()) {
517     // Post a task to run the method in the origin thread.
518     // Transfer the ownership of |signal| to RunMethod().
519     // |released_signal| will be deleted in RunMethod().
520     Signal* released_signal = signal.release();
521     bus_->GetOriginTaskRunner()->PostTask(
522         FROM_HERE, base::BindOnce(&ObjectProxy::RunMethod, this, iter->second,
523                                   released_signal));
524   } else {
525     // If the D-Bus thread is not used, just call the callback on the
526     // current thread. Transfer the ownership of |signal| to RunMethod().
527     Signal* released_signal = signal.release();
528     RunMethod(iter->second, released_signal);
529   }
530
531   // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
532   // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
533   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
534 }
535
536 void ObjectProxy::RunMethod(std::vector<SignalCallback> signal_callbacks,
537                             Signal* signal) {
538   bus_->AssertOnOriginThread();
539
540   for (auto& signal_callback : signal_callbacks) {
541     signal_callback.Run(signal);
542   }
543
544   // Delete the message on the D-Bus thread. See comments in
545   // RunResponseOrErrorCallback().
546   bus_->GetDBusTaskRunner()->PostTask(
547       FROM_HERE, base::BindOnce(&base::DeletePointer<Signal>, signal));
548 }
549
550 DBusHandlerResult ObjectProxy::HandleMessageThunk(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
557 void ObjectProxy::LogMethodCallFailure(
558     const base::StringPiece& interface_name,
559     const base::StringPiece& method_name,
560     const base::StringPiece& error_name,
561     const base::StringPiece& error_message) const {
562   if (ignore_service_unknown_errors_ &&
563       (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
564     return;
565
566   std::ostringstream msg;
567   msg << "Failed to call method: " << interface_name << "." << method_name
568       << ": object_path= " << object_path_.value() << ": " << error_name << ": "
569       << error_message;
570
571   // "UnknownObject" indicates that an object or service is no longer available,
572   // e.g. a Shill network service has gone out of range. Treat these as warnings
573   // not errors.
574   if (error_name == kErrorObjectUnknown)
575     LOG(WARNING) << msg.str();
576   else
577     LOG(ERROR) << msg.str();
578 }
579
580 void ObjectProxy::OnCallMethod(const std::string& interface_name,
581                                const std::string& method_name,
582                                ResponseCallback response_callback,
583                                Response* response,
584                                ErrorResponse* error_response) {
585   if (response) {
586     // Method call was successful.
587     std::move(response_callback).Run(response);
588     return;
589   }
590   // Method call failed.
591   std::string error_name;
592   std::string error_message;
593   if (error_response) {
594     // Error message may contain the error message as string.
595     error_name = error_response->GetErrorName();
596     MessageReader reader(error_response);
597     reader.PopString(&error_message);
598   } else {
599     error_name = "unknown error type";
600   }
601   LogMethodCallFailure(interface_name, method_name, error_name, error_message);
602
603   std::move(response_callback).Run(nullptr);
604 }
605
606 bool ObjectProxy::AddMatchRuleWithCallback(
607     const std::string& match_rule,
608     const std::string& absolute_signal_name,
609     SignalCallback signal_callback) {
610   DCHECK(!match_rule.empty());
611   DCHECK(!absolute_signal_name.empty());
612   bus_->AssertOnDBusThread();
613
614   if (!base::Contains(match_rules_, match_rule)) {
615     dbus::Error error;
616     bus_->AddMatch(match_rule, &error);
617     if (error.IsValid()) {
618       LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
619                  << error.name() << ": " << error.message();
620       return false;
621     } else {
622       // Store the match rule, so that we can remove this in Detach().
623       match_rules_.insert(match_rule);
624       // Add the signal callback to the method table.
625       method_table_[absolute_signal_name].push_back(signal_callback);
626       return true;
627     }
628   }
629
630   // We already have the match rule.
631   method_table_[absolute_signal_name].push_back(signal_callback);
632   return true;
633 }
634
635 bool ObjectProxy::AddMatchRuleWithoutCallback(
636     const std::string& match_rule,
637     const std::string& absolute_signal_name) {
638   DCHECK(!match_rule.empty());
639   DCHECK(!absolute_signal_name.empty());
640   bus_->AssertOnDBusThread();
641
642   if (base::Contains(match_rules_, match_rule)) {
643     return true;
644   }
645
646   Error error;
647   bus_->AddMatch(match_rule, &error);
648   if (error.IsValid()) {
649     LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
650                << error.name() << ": " << error.message();
651     return false;
652   }
653   // Store the match rule, so that we can remove this in Detach().
654   match_rules_.insert(match_rule);
655   return true;
656 }
657
658 void ObjectProxy::UpdateNameOwnerAndBlock() {
659   bus_->AssertOnDBusThread();
660   // Errors should be suppressed here, as the service may not be yet running
661   // when connecting to signals of the service, which is just fine.
662   // The ObjectProxy will be notified when the service is launched via
663   // NameOwnerChanged signal. See also comments in ConnectToSignalAndBlock().
664   service_name_owner_ =
665       bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
666 }
667
668 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
669     std::unique_ptr<Signal> signal) {
670   DCHECK(signal);
671   bus_->AssertOnDBusThread();
672
673   // Confirm the validity of the NameOwnerChanged signal.
674   if (signal->GetMember() == kNameOwnerChangedMember &&
675       signal->GetInterface() == kDBusSystemObjectInterface &&
676       signal->GetSender() == kDBusSystemObjectAddress) {
677     MessageReader reader(signal.get());
678     std::string name, old_owner, new_owner;
679     if (reader.PopString(&name) && reader.PopString(&old_owner) &&
680         reader.PopString(&new_owner) && name == service_name_) {
681       service_name_owner_ = new_owner;
682       bus_->GetOriginTaskRunner()->PostTask(
683           FROM_HERE, base::BindOnce(&ObjectProxy::RunNameOwnerChangedCallback,
684                                     this, old_owner, new_owner));
685
686       const bool service_is_available = !service_name_owner_.empty();
687       if (service_is_available) {
688         bus_->GetOriginTaskRunner()->PostTask(
689             FROM_HERE,
690             base::BindOnce(
691                 &ObjectProxy::RunWaitForServiceToBeAvailableCallbacks, this,
692                 service_is_available));
693       }
694     }
695   }
696
697   // Always return unhandled to let other object proxies handle the same
698   // signal.
699   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
700 }
701
702 void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
703                                               const std::string& new_owner) {
704   bus_->AssertOnOriginThread();
705   if (!name_owner_changed_callback_.is_null())
706     name_owner_changed_callback_.Run(old_owner, new_owner);
707 }
708
709 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
710     bool service_is_available) {
711   bus_->AssertOnOriginThread();
712
713   std::vector<WaitForServiceToBeAvailableCallback> callbacks;
714   callbacks.swap(wait_for_service_to_be_available_callbacks_);
715   for (auto& callback : callbacks) {
716     std::move(callback).Run(service_is_available);
717   }
718 }
719
720 }  // namespace dbus