// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "dbus/object_proxy.h"

#include <stddef.h>
#include <utility>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/debug/leak_annotations.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "dbus/bus.h"
#include "dbus/dbus_statistics.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/scoped_dbus_error.h"
#include "dbus/util.h"

namespace dbus {

namespace {

constexpr char kErrorServiceUnknown[] =
    "org.freedesktop.DBus.Error.ServiceUnknown";
constexpr char kErrorObjectUnknown[] =
    "org.freedesktop.DBus.Error.UnknownObject";

// Used for success ratio histograms. 1 for success, 0 for failure.
constexpr int kSuccessRatioHistogramMaxValue = 2;

// The path of D-Bus Object sending NameOwnerChanged signal.
constexpr char kDBusSystemObjectPath[] = "/org/freedesktop/DBus";

// The D-Bus Object interface.
constexpr char kDBusSystemObjectInterface[] = "org.freedesktop.DBus";

// The D-Bus Object address.
constexpr char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";

// The NameOwnerChanged member in |kDBusSystemObjectInterface|.
constexpr char kNameOwnerChangedMember[] = "NameOwnerChanged";

}  // namespace

ObjectProxy::ReplyCallbackHolder::ReplyCallbackHolder(
    scoped_refptr<base::TaskRunner> origin_task_runner,
    ResponseOrErrorCallback callback)
    : origin_task_runner_(origin_task_runner), callback_(std::move(callback)) {
  DCHECK(origin_task_runner_.get());
  DCHECK(!callback_.is_null());
}

ObjectProxy::ReplyCallbackHolder::ReplyCallbackHolder(
    ReplyCallbackHolder&& other) = default;

ObjectProxy::ReplyCallbackHolder::~ReplyCallbackHolder() {
  if (callback_.is_null()) {
    // This is the regular case.
    // CallMethod and its family creates this object on the origin thread,
    // PostTask()s to the D-Bus thread for actual D-Bus communication,
    // then PostTask()s back to the origin thread to invoke the |callback_|.
    // At that timing, the ownership of callback should be released via
    // ReleaseCallback().
    // Otherwise, this instance was moved to another one. Do nothing in
    // either case.
    return;
  }

  // The only case where |origin_task_runner_| becomes nullptr is that
  // this is moved. In such a case, |callback_| should be nullptr, too, so it
  // should be handled above. Thus, here |origin_task_runner_| must not be
  // nullptr.
  DCHECK(origin_task_runner_.get());

  if (origin_task_runner_->RunsTasksInCurrentSequence()) {
    // Destroyed on the origin thread. This happens when PostTask()ing to
    // the D-Bus thread fails. The |callback_| can be destroyed on the
    // current thread safely. Do nothing here, and let member destruction
    // destroy the callback.
    return;
  }

  // Here is on D-Bus thread, so try to PostTask() to destroy the callback.
  // to the origin thread.
  // The |origin_task_runner_| may already have stopped. E.g., on Chrome's
  // shutdown the message loop of the UI thread (= the origin thread) stops
  // before D-Bus threaed's. In such a case, PostTask() fails. Because we
  // cannot do much thing here, instead, simply leak the callback rather than
  // destroying it on the D-Bus thread, which could be unexpected from the
  // direct or indirect caller of CallMethod.
  auto* callback_to_be_deleted =
      new ResponseOrErrorCallback(std::move(callback_));
  ANNOTATE_LEAKING_OBJECT_PTR(callback_to_be_deleted);
  origin_task_runner_->PostTask(
      FROM_HERE, base::BindOnce(&base::DeletePointer<ResponseOrErrorCallback>,
                                callback_to_be_deleted));
}

ObjectProxy::ResponseOrErrorCallback
ObjectProxy::ReplyCallbackHolder::ReleaseCallback() {
  DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
  return std::move(callback_);
}

ObjectProxy::ObjectProxy(Bus* bus,
                         const std::string& service_name,
                         const ObjectPath& object_path,
                         int options)
    : bus_(bus),
      service_name_(service_name),
      object_path_(object_path),
      ignore_service_unknown_errors_(
          options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
  LOG_IF(FATAL, !object_path_.IsValid()) << object_path_.value();
}

ObjectProxy::~ObjectProxy() {
  DCHECK(pending_calls_.empty());
}

// Originally we tried to make |method_call| a const reference, but we
// gave up as dbus_connection_send_with_reply_and_block() takes a
// non-const pointer of DBusMessage as the second parameter.
std::unique_ptr<Response> ObjectProxy::CallMethodAndBlockWithErrorDetails(
    MethodCall* method_call,
    int timeout_ms,
    ScopedDBusError* error) {
  bus_->AssertOnDBusThread();

  if (!bus_->Connect() ||
      !method_call->SetDestination(service_name_) ||
      !method_call->SetPath(object_path_))
    return std::unique_ptr<Response>();

  DBusMessage* request_message = method_call->raw_message();

  // Send the message synchronously.
  const base::TimeTicks start_time = base::TimeTicks::Now();
  DBusMessage* response_message =
      bus_->SendWithReplyAndBlock(request_message, timeout_ms, error->get());
  // Record if the method call is successful, or not. 1 if successful.
  UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
                            response_message ? 1 : 0,
                            kSuccessRatioHistogramMaxValue);
  statistics::AddBlockingSentMethodCall(service_name_,
                                        method_call->GetInterface(),
                                        method_call->GetMember());

  if (!response_message) {
    LogMethodCallFailure(method_call->GetInterface(),
                         method_call->GetMember(),
                         error->is_set() ? error->name() : "unknown error type",
                         error->is_set() ? error->message() : "");
    return std::unique_ptr<Response>();
  }
  // Record time spent for the method call. Don't include failures.
  UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
                      base::TimeTicks::Now() - start_time);

  return Response::FromRawMessage(response_message);
}

std::unique_ptr<Response> ObjectProxy::CallMethodAndBlock(
    MethodCall* method_call,
    int timeout_ms) {
  ScopedDBusError error;
  return CallMethodAndBlockWithErrorDetails(method_call, timeout_ms, &error);
}

void ObjectProxy::CallMethod(MethodCall* method_call,
                             int timeout_ms,
                             ResponseCallback callback) {
  auto internal_callback = base::BindOnce(
      &ObjectProxy::OnCallMethod, this, method_call->GetInterface(),
      method_call->GetMember(), std::move(callback));

  CallMethodWithErrorResponse(method_call, timeout_ms,
                              std::move(internal_callback));
}

void ObjectProxy::CallMethodWithErrorResponse(
    MethodCall* method_call,
    int timeout_ms,
    ResponseOrErrorCallback callback) {
  bus_->AssertOnOriginThread();

  const base::TimeTicks start_time = base::TimeTicks::Now();

  ReplyCallbackHolder callback_holder(bus_->GetOriginTaskRunner(),
                                      std::move(callback));

  if (!method_call->SetDestination(service_name_) ||
      !method_call->SetPath(object_path_)) {
    // In case of a failure, run the error callback with nullptr.
    base::OnceClosure task =
        base::BindOnce(&ObjectProxy::RunResponseOrErrorCallback, this,
                       std::move(callback_holder), start_time,
                       nullptr /* response */, nullptr /* error_response */);
    bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, std::move(task));
    return;
  }

  // Increment the reference count so we can safely reference the
  // underlying request message until the method call is complete. This
  // will be unref'ed in StartAsyncMethodCall().
  DBusMessage* request_message = method_call->raw_message();
  dbus_message_ref(request_message);

  statistics::AddSentMethodCall(service_name_,
                                method_call->GetInterface(),
                                method_call->GetMember());

  // Wait for the response in the D-Bus thread.
  base::OnceClosure task =
      base::BindOnce(&ObjectProxy::StartAsyncMethodCall, this, timeout_ms,
                     request_message, std::move(callback_holder), start_time);
  bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, std::move(task));
}

void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
                                              int timeout_ms,
                                              ResponseCallback callback,
                                              ErrorCallback error_callback) {
  auto internal_callback = base::BindOnce(
      [](ResponseCallback callback, ErrorCallback error_callback,
         Response* response, ErrorResponse* error_response) {
        if (response) {
          std::move(callback).Run(response);
        } else {
          std::move(error_callback).Run(error_response);
        }
      },
      std::move(callback), std::move(error_callback));

  CallMethodWithErrorResponse(method_call, timeout_ms,
                              std::move(internal_callback));
}

void ObjectProxy::ConnectToSignal(const std::string& interface_name,
                                  const std::string& signal_name,
                                  SignalCallback signal_callback,
                                  OnConnectedCallback on_connected_callback) {
  bus_->AssertOnOriginThread();

  if (bus_->HasDBusThread()) {
    base::PostTaskAndReplyWithResult(
        bus_->GetDBusTaskRunner(), FROM_HERE,
        base::BindOnce(&ObjectProxy::ConnectToSignalInternal, this,
                       interface_name, signal_name, signal_callback),
        base::BindOnce(std::move(on_connected_callback), interface_name,
                       signal_name));
  } else {
    // If the bus doesn't have a dedicated dbus thread we need to call
    // ConnectToSignalInternal directly otherwise we might miss a signal
    // that is currently queued if we do a PostTask.
    const bool success =
        ConnectToSignalInternal(interface_name, signal_name, signal_callback);
    std::move(on_connected_callback).Run(interface_name, signal_name, success);
  }
}

void ObjectProxy::SetNameOwnerChangedCallback(
    NameOwnerChangedCallback callback) {
  bus_->AssertOnOriginThread();

  name_owner_changed_callback_ = callback;
}

void ObjectProxy::WaitForServiceToBeAvailable(
    WaitForServiceToBeAvailableCallback callback) {
  bus_->AssertOnOriginThread();

  wait_for_service_to_be_available_callbacks_.push_back(std::move(callback));
  bus_->GetDBusTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(&ObjectProxy::WaitForServiceToBeAvailableInternal, this));
}

void ObjectProxy::Detach() {
  bus_->AssertOnDBusThread();

  if (bus_->is_connected())
    bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this);

  for (const auto& match_rule : match_rules_) {
    ScopedDBusError error;
    bus_->RemoveMatch(match_rule, error.get());
    if (error.is_set()) {
      // There is nothing we can do to recover, so just print the error.
      LOG(ERROR) << "Failed to remove match rule: " << match_rule;
    }
  }
  match_rules_.clear();

  for (auto* pending_call : pending_calls_) {
    dbus_pending_call_cancel(pending_call);
    dbus_pending_call_unref(pending_call);
  }
  pending_calls_.clear();
}

void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
                                       DBusMessage* request_message,
                                       ReplyCallbackHolder callback_holder,
                                       base::TimeTicks start_time) {
  bus_->AssertOnDBusThread();

  if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
    // In case of a failure, run the error callback with nullptr.
    base::OnceClosure task =
        base::BindOnce(&ObjectProxy::RunResponseOrErrorCallback, this,
                       std::move(callback_holder), start_time,
                       nullptr /* response */, nullptr /* error_response */);
    bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, std::move(task));

    dbus_message_unref(request_message);
    return;
  }

  DBusPendingCall* dbus_pending_call = nullptr;
  bus_->SendWithReply(request_message, &dbus_pending_call, timeout_ms);

  using PendingCallback =
      base::OnceCallback<void(DBusPendingCall * pending_call)>;
  // This returns false only when unable to allocate memory.
  const bool success = dbus_pending_call_set_notify(
      dbus_pending_call,
      [](DBusPendingCall* pending_call, void* user_data) {
        std::move(*static_cast<PendingCallback*>(user_data)).Run(pending_call);
      },
      // PendingCallback instance is owned by libdbus.
      new PendingCallback(base::BindOnce(&ObjectProxy::OnPendingCallIsComplete,
                                         this, std::move(callback_holder),
                                         start_time)),
      [](void* user_data) { delete static_cast<PendingCallback*>(user_data); });
  CHECK(success) << "Unable to allocate memory";
  pending_calls_.insert(dbus_pending_call);

  // It's now safe to unref the request message.
  dbus_message_unref(request_message);
}

void ObjectProxy::OnPendingCallIsComplete(ReplyCallbackHolder callback_holder,
                                          base::TimeTicks start_time,
                                          DBusPendingCall* pending_call) {
  bus_->AssertOnDBusThread();

  DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);

  // Either |response| or |error_response| takes ownership of the
  // |response_message|.
  std::unique_ptr<Response> response;
  std::unique_ptr<ErrorResponse> error_response;
  if (dbus_message_get_type(response_message) == DBUS_MESSAGE_TYPE_ERROR) {
    error_response = ErrorResponse::FromRawMessage(response_message);
  } else {
    response = Response::FromRawMessage(response_message);
  }

  base::OnceClosure task =
      base::BindOnce(&ObjectProxy::RunResponseOrErrorCallback, this,
                     std::move(callback_holder), start_time, response.get(),
                     error_response.get());

  // The message should be deleted on the D-Bus thread for a complicated
  // reason:
  //
  // libdbus keeps track of the number of bytes in the incoming message
  // queue to ensure that the data size in the queue is manageable. The
  // bookkeeping is partly done via dbus_message_unref(), and immediately
  // asks the client code (Chrome) to stop monitoring the underlying
  // socket, if the number of bytes exceeds a certian number, which is set
  // to 63MB, per dbus-transport.cc:
  //
  //   /* Try to default to something that won't totally hose the system,
  //    * but doesn't impose too much of a limitation.
  //    */
  //   transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
  //
  // The monitoring of the socket is done on the D-Bus thread (see Watch
  // class in bus.cc), hence we should stop the monitoring on D-Bus thread.
  bus_->GetOriginTaskRunner()->PostTaskAndReply(
      FROM_HERE, std::move(task),
      base::BindOnce(
          [](Response* response, ErrorResponse* error_response) {
            // Do nothing.
          },
          base::Owned(response.release()),
          base::Owned(error_response.release())));

  // Remove the pending call from the set.
  pending_calls_.erase(pending_call);
  dbus_pending_call_unref(pending_call);
}

void ObjectProxy::RunResponseOrErrorCallback(
    ReplyCallbackHolder callback_holder,
    base::TimeTicks start_time,
    Response* response,
    ErrorResponse* error_response) {
  bus_->AssertOnOriginThread();
  callback_holder.ReleaseCallback().Run(response, error_response);

  if (response) {
    // Record time spent for the method call. Don't include failures.
    UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
                        base::TimeTicks::Now() - start_time);
  }
  // Record if the method call is successful, or not. 1 if successful.
  UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess", response ? 1 : 0,
                            kSuccessRatioHistogramMaxValue);
}

bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
  bus_->AssertOnDBusThread();

  if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
    return false;

  bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this);

  // Add a match_rule listening NameOwnerChanged for the well-known name
  // |service_name_|.
  const std::string name_owner_changed_match_rule =
      base::StringPrintf(
          "type='signal',interface='org.freedesktop.DBus',"
          "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
          "sender='org.freedesktop.DBus',arg0='%s'",
          service_name_.c_str());

  const bool success =
      AddMatchRuleWithoutCallback(name_owner_changed_match_rule,
                                  "org.freedesktop.DBus.NameOwnerChanged");

  // Try getting the current name owner. It's not guaranteed that we can get
  // the name owner at this moment, as the service may not yet be started. If
  // that's the case, we'll get the name owner via NameOwnerChanged signal,
  // as soon as the service is started.
  UpdateNameOwnerAndBlock();

  return success;
}

bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name,
                                          const std::string& signal_name,
                                          SignalCallback signal_callback) {
  bus_->AssertOnDBusThread();

  if (!ConnectToNameOwnerChangedSignal())
    return false;

  const std::string absolute_signal_name =
      GetAbsoluteMemberName(interface_name, signal_name);

  // Add a match rule so the signal goes through HandleMessage().
  const std::string match_rule =
      base::StringPrintf("type='signal', interface='%s', path='%s'",
                         interface_name.c_str(),
                         object_path_.value().c_str());
  return AddMatchRuleWithCallback(match_rule,
                                  absolute_signal_name,
                                  signal_callback);
}

void ObjectProxy::WaitForServiceToBeAvailableInternal() {
  bus_->AssertOnDBusThread();

  if (!ConnectToNameOwnerChangedSignal()) {  // Failed to connect to the signal.
    const bool service_is_ready = false;
    bus_->GetOriginTaskRunner()->PostTask(
        FROM_HERE,
        base::BindOnce(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
                       this, service_is_ready));
    return;
  }

  const bool service_is_available = !service_name_owner_.empty();
  if (service_is_available) {  // Service is already available.
    bus_->GetOriginTaskRunner()->PostTask(
        FROM_HERE,
        base::BindOnce(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
                       this, service_is_available));
    return;
  }
}

DBusHandlerResult ObjectProxy::HandleMessage(
    DBusConnection* connection,
    DBusMessage* raw_message) {
  bus_->AssertOnDBusThread();

  if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

  // raw_message will be unrefed on exit of the function. Increment the
  // reference so we can use it in Signal.
  dbus_message_ref(raw_message);
  std::unique_ptr<Signal> signal(Signal::FromRawMessage(raw_message));

  // Verify the signal comes from the object we're proxying for, this is
  // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
  // allow other object proxies to handle instead.
  const ObjectPath path = signal->GetPath();
  if (path != object_path_) {
    if (path.value() == kDBusSystemObjectPath &&
        signal->GetMember() == kNameOwnerChangedMember) {
      // Handle NameOwnerChanged separately
      return HandleNameOwnerChanged(std::move(signal));
    }
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  }

  const std::string interface = signal->GetInterface();
  const std::string member = signal->GetMember();

  statistics::AddReceivedSignal(service_name_, interface, member);

  // Check if we know about the signal.
  const std::string absolute_signal_name = GetAbsoluteMemberName(
      interface, member);
  MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
  if (iter == method_table_.end()) {
    // Don't know about the signal.
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  }
  VLOG(1) << "Signal received: " << signal->ToString();

  std::string sender = signal->GetSender();
  if (service_name_owner_ != sender) {
    LOG(ERROR) << "Rejecting a message from a wrong sender.";
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  }

  const base::TimeTicks start_time = base::TimeTicks::Now();
  if (bus_->HasDBusThread()) {
    // Post a task to run the method in the origin thread.
    // Transfer the ownership of |signal| to RunMethod().
    // |released_signal| will be deleted in RunMethod().
    Signal* released_signal = signal.release();
    bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
                                          base::Bind(&ObjectProxy::RunMethod,
                                                     this,
                                                     start_time,
                                                     iter->second,
                                                     released_signal));
  } else {
    const base::TimeTicks start_time = base::TimeTicks::Now();
    // If the D-Bus thread is not used, just call the callback on the
    // current thread. Transfer the ownership of |signal| to RunMethod().
    Signal* released_signal = signal.release();
    RunMethod(start_time, iter->second, released_signal);
  }

  // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
  // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

void ObjectProxy::RunMethod(base::TimeTicks start_time,
                            std::vector<SignalCallback> signal_callbacks,
                            Signal* signal) {
  bus_->AssertOnOriginThread();

  for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin();
       iter != signal_callbacks.end(); ++iter)
    iter->Run(signal);

  // Delete the message on the D-Bus thread. See comments in
  // RunResponseOrErrorCallback().
  bus_->GetDBusTaskRunner()->PostTask(
      FROM_HERE,
      base::Bind(&base::DeletePointer<Signal>, signal));

  // Record time spent for handling the signal.
  UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
                      base::TimeTicks::Now() - start_time);
}

DBusHandlerResult ObjectProxy::HandleMessageThunk(
    DBusConnection* connection,
    DBusMessage* raw_message,
    void* user_data) {
  ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
  return self->HandleMessage(connection, raw_message);
}

void ObjectProxy::LogMethodCallFailure(
    const base::StringPiece& interface_name,
    const base::StringPiece& method_name,
    const base::StringPiece& error_name,
    const base::StringPiece& error_message) const {
  if (ignore_service_unknown_errors_ &&
      (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
    return;

  std::ostringstream msg;
  msg << "Failed to call method: " << interface_name << "." << method_name
      << ": object_path= " << object_path_.value()
      << ": " << error_name << ": " << error_message;

  // "UnknownObject" indicates that an object or service is no longer available,
  // e.g. a Shill network service has gone out of range. Treat these as warnings
  // not errors.
  if (error_name == kErrorObjectUnknown)
    LOG(WARNING) << msg.str();
  else
    LOG(ERROR) << msg.str();
}

void ObjectProxy::OnCallMethod(const std::string& interface_name,
                               const std::string& method_name,
                               ResponseCallback response_callback,
                               Response* response,
                               ErrorResponse* error_response) {
  if (response) {
    // Method call was successful.
    std::move(response_callback).Run(response);
    return;
  }
  // Method call failed.
  std::string error_name;
  std::string error_message;
  if (error_response) {
    // Error message may contain the error message as string.
    error_name = error_response->GetErrorName();
    MessageReader reader(error_response);
    reader.PopString(&error_message);
  } else {
    error_name = "unknown error type";
  }
  LogMethodCallFailure(interface_name, method_name, error_name, error_message);

  std::move(response_callback).Run(nullptr);
}

bool ObjectProxy::AddMatchRuleWithCallback(
    const std::string& match_rule,
    const std::string& absolute_signal_name,
    SignalCallback signal_callback) {
  DCHECK(!match_rule.empty());
  DCHECK(!absolute_signal_name.empty());
  bus_->AssertOnDBusThread();

  if (match_rules_.find(match_rule) == match_rules_.end()) {
    ScopedDBusError error;
    bus_->AddMatch(match_rule, error.get());
    if (error.is_set()) {
      LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
                 << error.name() << ": " << error.message();
      return false;
    } else {
      // Store the match rule, so that we can remove this in Detach().
      match_rules_.insert(match_rule);
      // Add the signal callback to the method table.
      method_table_[absolute_signal_name].push_back(signal_callback);
      return true;
    }
  } else {
    // We already have the match rule.
    method_table_[absolute_signal_name].push_back(signal_callback);
    return true;
  }
}

bool ObjectProxy::AddMatchRuleWithoutCallback(
    const std::string& match_rule,
    const std::string& absolute_signal_name) {
  DCHECK(!match_rule.empty());
  DCHECK(!absolute_signal_name.empty());
  bus_->AssertOnDBusThread();

  if (match_rules_.find(match_rule) != match_rules_.end())
    return true;

  ScopedDBusError error;
  bus_->AddMatch(match_rule, error.get());
  if (error.is_set()) {
    LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
               << error.name() << ": " << error.message();
    return false;
  }
  // Store the match rule, so that we can remove this in Detach().
  match_rules_.insert(match_rule);
  return true;
}

void ObjectProxy::UpdateNameOwnerAndBlock() {
  bus_->AssertOnDBusThread();
  // Errors should be suppressed here, as the service may not be yet running
  // when connecting to signals of the service, which is just fine.
  // The ObjectProxy will be notified when the service is launched via
  // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
  service_name_owner_ =
      bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
}

DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
    std::unique_ptr<Signal> signal) {
  DCHECK(signal);
  bus_->AssertOnDBusThread();

  // Confirm the validity of the NameOwnerChanged signal.
  if (signal->GetMember() == kNameOwnerChangedMember &&
      signal->GetInterface() == kDBusSystemObjectInterface &&
      signal->GetSender() == kDBusSystemObjectAddress) {
    MessageReader reader(signal.get());
    std::string name, old_owner, new_owner;
    if (reader.PopString(&name) &&
        reader.PopString(&old_owner) &&
        reader.PopString(&new_owner) &&
        name == service_name_) {
      service_name_owner_ = new_owner;
      bus_->GetOriginTaskRunner()->PostTask(
          FROM_HERE,
          base::Bind(&ObjectProxy::RunNameOwnerChangedCallback,
                     this, old_owner, new_owner));

      const bool service_is_available = !service_name_owner_.empty();
      if (service_is_available) {
        bus_->GetOriginTaskRunner()->PostTask(
            FROM_HERE,
            base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
                       this, service_is_available));
      }
    }
  }

  // Always return unhandled to let other object proxies handle the same
  // signal.
  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
                                              const std::string& new_owner) {
  bus_->AssertOnOriginThread();
  if (!name_owner_changed_callback_.is_null())
    name_owner_changed_callback_.Run(old_owner, new_owner);
}

void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
    bool service_is_available) {
  bus_->AssertOnOriginThread();

  std::vector<WaitForServiceToBeAvailableCallback> callbacks;
  callbacks.swap(wait_for_service_to_be_available_callbacks_);
  for (size_t i = 0; i < callbacks.size(); ++i)
    std::move(callbacks[i]).Run(service_is_available);
}

}  // namespace dbus
