• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/string_piece.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/task_runner_util.h"
17 #include "base/threading/thread.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "dbus/bus.h"
20 #include "dbus/dbus_statistics.h"
21 #include "dbus/message.h"
22 #include "dbus/object_path.h"
23 #include "dbus/scoped_dbus_error.h"
24 #include "dbus/util.h"
25 
26 namespace dbus {
27 
28 namespace {
29 
30 const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown";
31 const char kErrorObjectUnknown[] = "org.freedesktop.DBus.Error.UnknownObject";
32 
33 // Used for success ratio histograms. 1 for success, 0 for failure.
34 const int kSuccessRatioHistogramMaxValue = 2;
35 
36 // The path of D-Bus Object sending NameOwnerChanged signal.
37 const char kDBusSystemObjectPath[] = "/org/freedesktop/DBus";
38 
39 // The D-Bus Object interface.
40 const char kDBusSystemObjectInterface[] = "org.freedesktop.DBus";
41 
42 // The D-Bus Object address.
43 const char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";
44 
45 // The NameOwnerChanged member in |kDBusSystemObjectInterface|.
46 const char kNameOwnerChangedMember[] = "NameOwnerChanged";
47 
48 // An empty function used for ObjectProxy::EmptyResponseCallback().
EmptyResponseCallbackBody(Response *)49 void EmptyResponseCallbackBody(Response* /*response*/) {
50 }
51 
52 }  // namespace
53 
ObjectProxy(Bus * bus,const std::string & service_name,const ObjectPath & object_path,int options)54 ObjectProxy::ObjectProxy(Bus* bus,
55                          const std::string& service_name,
56                          const ObjectPath& object_path,
57                          int options)
58     : bus_(bus),
59       service_name_(service_name),
60       object_path_(object_path),
61       ignore_service_unknown_errors_(
62           options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
63 }
64 
~ObjectProxy()65 ObjectProxy::~ObjectProxy() {
66   DCHECK(pending_calls_.empty());
67 }
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.
CallMethodAndBlockWithErrorDetails(MethodCall * method_call,int timeout_ms,ScopedDBusError * error)72 std::unique_ptr<Response> ObjectProxy::CallMethodAndBlockWithErrorDetails(
73     MethodCall* method_call,
74     int timeout_ms,
75     ScopedDBusError* error) {
76   bus_->AssertOnDBusThread();
77 
78   if (!bus_->Connect() ||
79       !method_call->SetDestination(service_name_) ||
80       !method_call->SetPath(object_path_))
81     return std::unique_ptr<Response>();
82 
83   DBusMessage* request_message = method_call->raw_message();
84 
85   // Send the message synchronously.
86   const base::TimeTicks start_time = base::TimeTicks::Now();
87   DBusMessage* response_message =
88       bus_->SendWithReplyAndBlock(request_message, timeout_ms, error->get());
89   // 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);
93   statistics::AddBlockingSentMethodCall(service_name_,
94                                         method_call->GetInterface(),
95                                         method_call->GetMember());
96 
97   if (!response_message) {
98     LogMethodCallFailure(method_call->GetInterface(),
99                          method_call->GetMember(),
100                          error->is_set() ? error->name() : "unknown error type",
101                          error->is_set() ? error->message() : "");
102     return std::unique_ptr<Response>();
103   }
104   // Record time spent for the method call. Don't include failures.
105   UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
106                       base::TimeTicks::Now() - start_time);
107 
108   return Response::FromRawMessage(response_message);
109 }
110 
CallMethodAndBlock(MethodCall * method_call,int timeout_ms)111 std::unique_ptr<Response> ObjectProxy::CallMethodAndBlock(
112     MethodCall* method_call,
113     int timeout_ms) {
114   ScopedDBusError error;
115   return CallMethodAndBlockWithErrorDetails(method_call, timeout_ms, &error);
116 }
117 
CallMethod(MethodCall * method_call,int timeout_ms,ResponseCallback callback)118 void ObjectProxy::CallMethod(MethodCall* method_call,
119                              int timeout_ms,
120                              ResponseCallback callback) {
121   CallMethodWithErrorCallback(method_call, timeout_ms, callback,
122                               base::Bind(&ObjectProxy::OnCallMethodError,
123                                          this,
124                                          method_call->GetInterface(),
125                                          method_call->GetMember(),
126                                          callback));
127 }
128 
CallMethodWithErrorCallback(MethodCall * method_call,int timeout_ms,ResponseCallback callback,ErrorCallback error_callback)129 void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
130                                               int timeout_ms,
131                                               ResponseCallback callback,
132                                               ErrorCallback error_callback) {
133   bus_->AssertOnOriginThread();
134 
135   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);
147     bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
148     return;
149   }
150 
151   // 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 
157   base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall,
158                                   this,
159                                   timeout_ms,
160                                   request_message,
161                                   callback,
162                                   error_callback,
163                                   start_time);
164   statistics::AddSentMethodCall(service_name_,
165                                 method_call->GetInterface(),
166                                 method_call->GetMember());
167 
168   // Wait for the response in the D-Bus thread.
169   bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
170 }
171 
ConnectToSignal(const std::string & interface_name,const std::string & signal_name,SignalCallback signal_callback,OnConnectedCallback on_connected_callback)172 void 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 
178   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   }
192 }
193 
SetNameOwnerChangedCallback(NameOwnerChangedCallback callback)194 void ObjectProxy::SetNameOwnerChangedCallback(
195     NameOwnerChangedCallback callback) {
196   bus_->AssertOnOriginThread();
197 
198   name_owner_changed_callback_ = callback;
199 }
200 
WaitForServiceToBeAvailable(WaitForServiceToBeAvailableCallback callback)201 void 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 
Detach()211 void ObjectProxy::Detach() {
212   bus_->AssertOnDBusThread();
213 
214   if (bus_->is_connected())
215     bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this);
216 
217   for (const auto& match_rule : match_rules_) {
218     ScopedDBusError error;
219     bus_->RemoveMatch(match_rule, error.get());
220     if (error.is_set()) {
221       // There is nothing we can do to recover, so just print the error.
222       LOG(ERROR) << "Failed to remove match rule: " << match_rule;
223     }
224   }
225   match_rules_.clear();
226 
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();
232 }
233 
234 // static
EmptyResponseCallback()235 ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() {
236   return base::Bind(&EmptyResponseCallbackBody);
237 }
238 
OnPendingCallIsCompleteData(ObjectProxy * in_object_proxy,ResponseCallback in_response_callback,ErrorCallback in_error_callback,base::TimeTicks in_start_time)239 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
240     ObjectProxy* in_object_proxy,
241     ResponseCallback in_response_callback,
242     ErrorCallback in_error_callback,
243     base::TimeTicks in_start_time)
244     : object_proxy(in_object_proxy),
245       response_callback(in_response_callback),
246       error_callback(in_error_callback),
247       start_time(in_start_time) {
248 }
249 
~OnPendingCallIsCompleteData()250 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
251 }
252 
StartAsyncMethodCall(int timeout_ms,DBusMessage * request_message,ResponseCallback response_callback,ErrorCallback error_callback,base::TimeTicks start_time)253 void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
254                                        DBusMessage* request_message,
255                                        ResponseCallback response_callback,
256                                        ErrorCallback error_callback,
257                                        base::TimeTicks start_time) {
258   bus_->AssertOnDBusThread();
259 
260   if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
261     // In case of a failure, run the error callback with NULL.
262     DBusMessage* response_message = NULL;
263     base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
264                                     this,
265                                     response_callback,
266                                     error_callback,
267                                     start_time,
268                                     response_message);
269     bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
270 
271     dbus_message_unref(request_message);
272     return;
273   }
274 
275   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 =
282       new OnPendingCallIsCompleteData(this, response_callback, error_callback,
283                                       start_time);
284 
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,
290       &DeleteVoidPointer<OnPendingCallIsCompleteData>);
291   CHECK(success) << "Unable to allocate memory";
292   pending_calls_.insert(pending_call);
293 
294   // It's now safe to unref the request message.
295   dbus_message_unref(request_message);
296 }
297 
OnPendingCallIsComplete(DBusPendingCall * pending_call,ResponseCallback response_callback,ErrorCallback error_callback,base::TimeTicks start_time)298 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
299                                           ResponseCallback response_callback,
300                                           ErrorCallback error_callback,
301                                           base::TimeTicks start_time) {
302   bus_->AssertOnDBusThread();
303 
304   DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
305   base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
306                                   this,
307                                   response_callback,
308                                   error_callback,
309                                   start_time,
310                                   response_message);
311   bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
312 
313   // Remove the pending call from the set.
314   pending_calls_.erase(pending_call);
315   dbus_pending_call_unref(pending_call);
316 }
317 
RunResponseCallback(ResponseCallback response_callback,ErrorCallback error_callback,base::TimeTicks start_time,DBusMessage * response_message)318 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
319                                       ErrorCallback error_callback,
320                                       base::TimeTicks start_time,
321                                       DBusMessage* response_message) {
322   bus_->AssertOnOriginThread();
323 
324   bool method_call_successful = false;
325   if (!response_message) {
326     // The response is not received.
327     error_callback.Run(NULL);
328   } else if (dbus_message_get_type(response_message) ==
329              DBUS_MESSAGE_TYPE_ERROR) {
330     // This will take |response_message| and release (unref) it.
331     std::unique_ptr<ErrorResponse> error_response(
332         ErrorResponse::FromRawMessage(response_message));
333     error_callback.Run(error_response.get());
334     // Delete the message  on the D-Bus thread. See below for why.
335     bus_->GetDBusTaskRunner()->PostTask(
336         FROM_HERE,
337         base::Bind(&base::DeletePointer<ErrorResponse>,
338                    error_response.release()));
339   } else {
340     // This will take |response_message| and release (unref) it.
341     std::unique_ptr<Response> response(
342         Response::FromRawMessage(response_message));
343     // The response is successfully received.
344     response_callback.Run(response.get());
345     // 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.
363     bus_->GetDBusTaskRunner()->PostTask(
364         FROM_HERE,
365         base::Bind(&base::DeletePointer<Response>, response.release()));
366 
367     method_call_successful = true;
368     // Record time spent for the method call. Don't include failures.
369     UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
370                         base::TimeTicks::Now() - start_time);
371   }
372   // Record if the method call is successful, or not. 1 if successful.
373   UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
374                             method_call_successful,
375                             kSuccessRatioHistogramMaxValue);
376 }
377 
OnPendingCallIsCompleteThunk(DBusPendingCall * pending_call,void * user_data)378 void 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,
384                                 data->response_callback,
385                                 data->error_callback,
386                                 data->start_time);
387 }
388 
ConnectToNameOwnerChangedSignal()389 bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
390   bus_->AssertOnDBusThread();
391 
392   if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
393     return false;
394 
395   bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this);
396 
397   // 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());
405 
406   const bool success =
407       AddMatchRuleWithoutCallback(name_owner_changed_match_rule,
408                                   "org.freedesktop.DBus.NameOwnerChanged");
409 
410   // 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();
415 
416   return success;
417 }
418 
ConnectToSignalInternal(const std::string & interface_name,const std::string & signal_name,SignalCallback signal_callback)419 bool 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 =
428       GetAbsoluteMemberName(interface_name, signal_name);
429 
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 
WaitForServiceToBeAvailableInternal()440 void 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 
HandleMessage(DBusConnection *,DBusMessage * raw_message)462 DBusHandlerResult ObjectProxy::HandleMessage(DBusConnection*,
463                                              DBusMessage* raw_message) {
464   bus_->AssertOnDBusThread();
465 
466   if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
467     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
468 
469   // raw_message will be unrefed on exit of the function. Increment the
470   // reference so we can use it in Signal.
471   dbus_message_ref(raw_message);
472   std::unique_ptr<Signal> signal(Signal::FromRawMessage(raw_message));
473 
474   // Verify the signal comes from the object we're proxying for, this is
475   // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
476   // allow other object proxies to handle instead.
477   const ObjectPath path = signal->GetPath();
478   if (path != object_path_) {
479     if (path.value() == kDBusSystemObjectPath &&
480         signal->GetMember() == kNameOwnerChangedMember) {
481       // Handle NameOwnerChanged separately
482       return HandleNameOwnerChanged(std::move(signal));
483     }
484     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
485   }
486 
487   const std::string interface = signal->GetInterface();
488   const std::string member = signal->GetMember();
489 
490   statistics::AddReceivedSignal(service_name_, interface, member);
491 
492   // Check if we know about the signal.
493   const std::string absolute_signal_name = GetAbsoluteMemberName(
494       interface, member);
495   MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
496   if (iter == method_table_.end()) {
497     // Don't know about the signal.
498     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
499   }
500   VLOG(1) << "Signal received: " << signal->ToString();
501 
502   std::string sender = signal->GetSender();
503   if (service_name_owner_ != sender) {
504     LOG(ERROR) << "Rejecting a message from a wrong sender.";
505     UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
506     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
507   }
508 
509   const base::TimeTicks start_time = base::TimeTicks::Now();
510   if (bus_->HasDBusThread()) {
511     // Post a task to run the method in the origin thread.
512     // Transfer the ownership of |signal| to RunMethod().
513     // |released_signal| will be deleted in RunMethod().
514     Signal* released_signal = signal.release();
515     bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
516                                           base::Bind(&ObjectProxy::RunMethod,
517                                                      this,
518                                                      start_time,
519                                                      iter->second,
520                                                      released_signal));
521   } else {
522     const base::TimeTicks start_time = base::TimeTicks::Now();
523     // If the D-Bus thread is not used, just call the callback on the
524     // current thread. Transfer the ownership of |signal| to RunMethod().
525     Signal* released_signal = signal.release();
526     RunMethod(start_time, iter->second, released_signal);
527   }
528 
529   // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
530   // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
531   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
532 }
533 
RunMethod(base::TimeTicks start_time,std::vector<SignalCallback> signal_callbacks,Signal * signal)534 void ObjectProxy::RunMethod(base::TimeTicks start_time,
535                             std::vector<SignalCallback> signal_callbacks,
536                             Signal* signal) {
537   bus_->AssertOnOriginThread();
538 
539   for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin();
540        iter != signal_callbacks.end(); ++iter)
541     iter->Run(signal);
542 
543   // Delete the message on the D-Bus thread. See comments in
544   // RunResponseCallback().
545   bus_->GetDBusTaskRunner()->PostTask(
546       FROM_HERE,
547       base::Bind(&base::DeletePointer<Signal>, signal));
548 
549   // Record time spent for handling the signal.
550   UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
551                       base::TimeTicks::Now() - start_time);
552 }
553 
HandleMessageThunk(DBusConnection * connection,DBusMessage * raw_message,void * user_data)554 DBusHandlerResult ObjectProxy::HandleMessageThunk(
555     DBusConnection* connection,
556     DBusMessage* raw_message,
557     void* user_data) {
558   ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
559   return self->HandleMessage(connection, raw_message);
560 }
561 
LogMethodCallFailure(const base::StringPiece & interface_name,const base::StringPiece & method_name,const base::StringPiece & error_name,const base::StringPiece & error_message) const562 void ObjectProxy::LogMethodCallFailure(
563     const base::StringPiece& interface_name,
564     const base::StringPiece& method_name,
565     const base::StringPiece& error_name,
566     const base::StringPiece& error_message) const {
567   if (ignore_service_unknown_errors_ &&
568       (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
569     return;
570 
571   std::ostringstream msg;
572   msg << "Failed to call method: " << interface_name << "." << method_name
573       << ": object_path= " << object_path_.value()
574       << ": " << error_name << ": " << error_message;
575 
576   // "UnknownObject" indicates that an object or service is no longer available,
577   // e.g. a Shill network service has gone out of range. Treat these as warnings
578   // not errors.
579   if (error_name == kErrorObjectUnknown)
580     LOG(WARNING) << msg.str();
581   else
582     LOG(ERROR) << msg.str();
583 }
584 
OnCallMethodError(const std::string & interface_name,const std::string & method_name,ResponseCallback response_callback,ErrorResponse * error_response)585 void ObjectProxy::OnCallMethodError(const std::string& interface_name,
586                                     const std::string& method_name,
587                                     ResponseCallback response_callback,
588                                     ErrorResponse* error_response) {
589   if (error_response) {
590     // Error message may contain the error message as string.
591     MessageReader reader(error_response);
592     std::string error_message;
593     reader.PopString(&error_message);
594     LogMethodCallFailure(interface_name,
595                          method_name,
596                          error_response->GetErrorName(),
597                          error_message);
598   }
599   response_callback.Run(NULL);
600 }
601 
AddMatchRuleWithCallback(const std::string & match_rule,const std::string & absolute_signal_name,SignalCallback signal_callback)602 bool ObjectProxy::AddMatchRuleWithCallback(
603     const std::string& match_rule,
604     const std::string& absolute_signal_name,
605     SignalCallback signal_callback) {
606   DCHECK(!match_rule.empty());
607   DCHECK(!absolute_signal_name.empty());
608   bus_->AssertOnDBusThread();
609 
610   if (match_rules_.find(match_rule) == match_rules_.end()) {
611     ScopedDBusError error;
612     bus_->AddMatch(match_rule, error.get());
613     if (error.is_set()) {
614       LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
615                  << error.name() << ": " << error.message();
616       return false;
617     } else {
618       // Store the match rule, so that we can remove this in Detach().
619       match_rules_.insert(match_rule);
620       // Add the signal callback to the method table.
621       method_table_[absolute_signal_name].push_back(signal_callback);
622       return true;
623     }
624   } else {
625     // We already have the match rule.
626     method_table_[absolute_signal_name].push_back(signal_callback);
627     return true;
628   }
629 }
630 
AddMatchRuleWithoutCallback(const std::string & match_rule,const std::string & absolute_signal_name)631 bool ObjectProxy::AddMatchRuleWithoutCallback(
632     const std::string& match_rule,
633     const std::string& absolute_signal_name) {
634   DCHECK(!match_rule.empty());
635   DCHECK(!absolute_signal_name.empty());
636   bus_->AssertOnDBusThread();
637 
638   if (match_rules_.find(match_rule) != match_rules_.end())
639     return true;
640 
641   ScopedDBusError error;
642   bus_->AddMatch(match_rule, error.get());
643   if (error.is_set()) {
644     LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
645                << error.name() << ": " << error.message();
646     return false;
647   }
648   // Store the match rule, so that we can remove this in Detach().
649   match_rules_.insert(match_rule);
650   return true;
651 }
652 
UpdateNameOwnerAndBlock()653 void ObjectProxy::UpdateNameOwnerAndBlock() {
654   bus_->AssertOnDBusThread();
655   // Errors should be suppressed here, as the service may not be yet running
656   // when connecting to signals of the service, which is just fine.
657   // The ObjectProxy will be notified when the service is launched via
658   // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
659   service_name_owner_ =
660       bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
661 }
662 
HandleNameOwnerChanged(std::unique_ptr<Signal> signal)663 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
664     std::unique_ptr<Signal> signal) {
665   DCHECK(signal);
666   bus_->AssertOnDBusThread();
667 
668   // Confirm the validity of the NameOwnerChanged signal.
669   if (signal->GetMember() == kNameOwnerChangedMember &&
670       signal->GetInterface() == kDBusSystemObjectInterface &&
671       signal->GetSender() == kDBusSystemObjectAddress) {
672     MessageReader reader(signal.get());
673     std::string name, old_owner, new_owner;
674     if (reader.PopString(&name) &&
675         reader.PopString(&old_owner) &&
676         reader.PopString(&new_owner) &&
677         name == service_name_) {
678       service_name_owner_ = new_owner;
679       bus_->GetOriginTaskRunner()->PostTask(
680           FROM_HERE,
681           base::Bind(&ObjectProxy::RunNameOwnerChangedCallback,
682                      this, old_owner, new_owner));
683 
684       const bool service_is_available = !service_name_owner_.empty();
685       if (service_is_available) {
686         bus_->GetOriginTaskRunner()->PostTask(
687             FROM_HERE,
688             base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
689                        this, service_is_available));
690       }
691     }
692   }
693 
694   // Always return unhandled to let other object proxies handle the same
695   // signal.
696   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
697 }
698 
RunNameOwnerChangedCallback(const std::string & old_owner,const std::string & new_owner)699 void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
700                                               const std::string& new_owner) {
701   bus_->AssertOnOriginThread();
702   if (!name_owner_changed_callback_.is_null())
703     name_owner_changed_callback_.Run(old_owner, new_owner);
704 }
705 
RunWaitForServiceToBeAvailableCallbacks(bool service_is_available)706 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
707     bool service_is_available) {
708   bus_->AssertOnOriginThread();
709 
710   std::vector<WaitForServiceToBeAvailableCallback> callbacks;
711   callbacks.swap(wait_for_service_to_be_available_callbacks_);
712   for (size_t i = 0; i < callbacks.size(); ++i)
713     callbacks[i].Run(service_is_available);
714 }
715 
716 }  // namespace dbus
717