Home | History | Annotate | Download | only in dbus
      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.
     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().
     53 void EmptyResponseCallbackBody(Response* /*response*/) {
     54 }
     55 
     56 }  // namespace
     57 
     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 
     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.
     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 
    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 
    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 
    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 
    188 void ObjectProxy::SetNameOwnerChangedCallback(
    189     NameOwnerChangedCallback callback) {
    190   bus_->AssertOnOriginThread();
    191 
    192   name_owner_changed_callback_ = callback;
    193 }
    194 
    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 
    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
    227 ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() {
    228   return base::Bind(&EmptyResponseCallbackBody);
    229 }
    230 
    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 
    242 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
    243 }
    244 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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   // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
    527   // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
    528   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    529 }
    530 
    531 void ObjectProxy::RunMethod(base::TimeTicks start_time,
    532                             std::vector<SignalCallback> signal_callbacks,
    533                             Signal* signal) {
    534   bus_->AssertOnOriginThread();
    535 
    536   for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin();
    537        iter != signal_callbacks.end(); ++iter)
    538     iter->Run(signal);
    539 
    540   // Delete the message on the D-Bus thread. See comments in
    541   // RunResponseCallback().
    542   bus_->GetDBusTaskRunner()->PostTask(
    543       FROM_HERE,
    544       base::Bind(&base::DeletePointer<Signal>, signal));
    545 
    546   // Record time spent for handling the signal.
    547   UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
    548                       base::TimeTicks::Now() - start_time);
    549 }
    550 
    551 DBusHandlerResult ObjectProxy::HandleMessageThunk(
    552     DBusConnection* connection,
    553     DBusMessage* raw_message,
    554     void* user_data) {
    555   ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
    556   return self->HandleMessage(connection, raw_message);
    557 }
    558 
    559 void ObjectProxy::LogMethodCallFailure(
    560     const base::StringPiece& interface_name,
    561     const base::StringPiece& method_name,
    562     const base::StringPiece& error_name,
    563     const base::StringPiece& error_message) const {
    564   if (ignore_service_unknown_errors_ && error_name == kErrorServiceUnknown)
    565     return;
    566   LOG(ERROR) << "Failed to call method: "
    567              << interface_name << "." << method_name
    568              << ": object_path= " << object_path_.value()
    569              << ": " << error_name << ": " << error_message;
    570 }
    571 
    572 void ObjectProxy::OnCallMethodError(const std::string& interface_name,
    573                                     const std::string& method_name,
    574                                     ResponseCallback response_callback,
    575                                     ErrorResponse* error_response) {
    576   if (error_response) {
    577     // Error message may contain the error message as string.
    578     MessageReader reader(error_response);
    579     std::string error_message;
    580     reader.PopString(&error_message);
    581     LogMethodCallFailure(interface_name,
    582                          method_name,
    583                          error_response->GetErrorName(),
    584                          error_message);
    585   }
    586   response_callback.Run(NULL);
    587 }
    588 
    589 bool ObjectProxy::AddMatchRuleWithCallback(
    590     const std::string& match_rule,
    591     const std::string& absolute_signal_name,
    592     SignalCallback signal_callback) {
    593   DCHECK(!match_rule.empty());
    594   DCHECK(!absolute_signal_name.empty());
    595   bus_->AssertOnDBusThread();
    596 
    597   if (match_rules_.find(match_rule) == match_rules_.end()) {
    598     ScopedDBusError error;
    599     bus_->AddMatch(match_rule, error.get());
    600     if (error.is_set()) {
    601       LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
    602                  << error.name() << ": " << error.message();
    603       return false;
    604     } else {
    605       // Store the match rule, so that we can remove this in Detach().
    606       match_rules_.insert(match_rule);
    607       // Add the signal callback to the method table.
    608       method_table_[absolute_signal_name].push_back(signal_callback);
    609       return true;
    610     }
    611   } else {
    612     // We already have the match rule.
    613     method_table_[absolute_signal_name].push_back(signal_callback);
    614     return true;
    615   }
    616 }
    617 
    618 bool ObjectProxy::AddMatchRuleWithoutCallback(
    619     const std::string& match_rule,
    620     const std::string& absolute_signal_name) {
    621   DCHECK(!match_rule.empty());
    622   DCHECK(!absolute_signal_name.empty());
    623   bus_->AssertOnDBusThread();
    624 
    625   if (match_rules_.find(match_rule) != match_rules_.end())
    626     return true;
    627 
    628   ScopedDBusError error;
    629   bus_->AddMatch(match_rule, error.get());
    630   if (error.is_set()) {
    631     LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
    632                << error.name() << ": " << error.message();
    633     return false;
    634   }
    635   // Store the match rule, so that we can remove this in Detach().
    636   match_rules_.insert(match_rule);
    637   return true;
    638 }
    639 
    640 void ObjectProxy::UpdateNameOwnerAndBlock() {
    641   bus_->AssertOnDBusThread();
    642   // Errors should be suppressed here, as the service may not be yet running
    643   // when connecting to signals of the service, which is just fine.
    644   // The ObjectProxy will be notified when the service is launched via
    645   // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
    646   service_name_owner_ =
    647       bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
    648 }
    649 
    650 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
    651     scoped_ptr<Signal> signal) {
    652   DCHECK(signal);
    653   bus_->AssertOnDBusThread();
    654 
    655   // Confirm the validity of the NameOwnerChanged signal.
    656   if (signal->GetMember() == kNameOwnerChangedMember &&
    657       signal->GetInterface() == kDBusSystemObjectInterface &&
    658       signal->GetSender() == kDBusSystemObjectAddress) {
    659     MessageReader reader(signal.get());
    660     std::string name, old_owner, new_owner;
    661     if (reader.PopString(&name) &&
    662         reader.PopString(&old_owner) &&
    663         reader.PopString(&new_owner) &&
    664         name == service_name_) {
    665       service_name_owner_ = new_owner;
    666       bus_->GetOriginTaskRunner()->PostTask(
    667           FROM_HERE,
    668           base::Bind(&ObjectProxy::RunNameOwnerChangedCallback,
    669                      this, old_owner, new_owner));
    670 
    671       const bool service_is_available = !service_name_owner_.empty();
    672       if (service_is_available) {
    673         bus_->GetOriginTaskRunner()->PostTask(
    674             FROM_HERE,
    675             base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
    676                        this, service_is_available));
    677       }
    678     }
    679   }
    680 
    681   // Always return unhandled to let other object proxies handle the same
    682   // signal.
    683   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    684 }
    685 
    686 void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
    687                                               const std::string& new_owner) {
    688   bus_->AssertOnOriginThread();
    689   if (!name_owner_changed_callback_.is_null())
    690     name_owner_changed_callback_.Run(old_owner, new_owner);
    691 }
    692 
    693 void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
    694     bool service_is_available) {
    695   bus_->AssertOnOriginThread();
    696 
    697   std::vector<WaitForServiceToBeAvailableCallback> callbacks;
    698   callbacks.swap(wait_for_service_to_be_available_callbacks_);
    699   for (size_t i = 0; i < callbacks.size(); ++i)
    700     callbacks[i].Run(service_is_available);
    701 }
    702 
    703 }  // namespace dbus
    704