object_proxy.cc 29 KB

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