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