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