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