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