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