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