object_manager.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. // Copyright (c) 2013 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_manager.h"
  5. #include <stddef.h>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/location.h"
  9. #include "base/logging.h"
  10. #include "base/metrics/histogram.h"
  11. #include "base/strings/stringprintf.h"
  12. #include "base/task/task_runner_util.h"
  13. #include "dbus/bus.h"
  14. #include "dbus/dbus_statistics.h"
  15. #include "dbus/message.h"
  16. #include "dbus/object_proxy.h"
  17. #include "dbus/property.h"
  18. #include "dbus/scoped_dbus_error.h"
  19. #include "dbus/util.h"
  20. namespace dbus {
  21. ObjectManager::Object::Object()
  22. : object_proxy(nullptr) {
  23. }
  24. ObjectManager::Object::~Object() = default;
  25. scoped_refptr<ObjectManager> ObjectManager::Create(
  26. Bus* bus,
  27. const std::string& service_name,
  28. const ObjectPath& object_path) {
  29. auto object_manager =
  30. base::WrapRefCounted(new ObjectManager(bus, service_name, object_path));
  31. // Set up a match rule and a filter function to handle PropertiesChanged
  32. // signals from the service. This is important to avoid any race conditions
  33. // that might cause us to miss PropertiesChanged signals once all objects are
  34. // initialized via GetManagedObjects.
  35. base::PostTaskAndReplyWithResult(
  36. bus->GetDBusTaskRunner(), FROM_HERE,
  37. base::BindOnce(&ObjectManager::SetupMatchRuleAndFilter, object_manager),
  38. base::BindOnce(&ObjectManager::OnSetupMatchRuleAndFilterComplete,
  39. object_manager));
  40. return object_manager;
  41. }
  42. ObjectManager::ObjectManager(Bus* bus,
  43. const std::string& service_name,
  44. const ObjectPath& object_path)
  45. : bus_(bus),
  46. service_name_(service_name),
  47. object_path_(object_path),
  48. setup_success_(false),
  49. cleanup_called_(false) {
  50. LOG_IF(FATAL, !object_path_.IsValid()) << object_path_.value();
  51. DVLOG(1) << "Creating ObjectManager for " << service_name_
  52. << " " << object_path_.value();
  53. DCHECK(bus_);
  54. bus_->AssertOnOriginThread();
  55. object_proxy_ = bus_->GetObjectProxy(service_name_, object_path_);
  56. object_proxy_->SetNameOwnerChangedCallback(base::BindRepeating(
  57. &ObjectManager::NameOwnerChanged, weak_ptr_factory_.GetWeakPtr()));
  58. }
  59. ObjectManager::~ObjectManager() {
  60. // Clean up Object structures
  61. for (ObjectMap::iterator iter = object_map_.begin();
  62. iter != object_map_.end(); ++iter) {
  63. Object* object = iter->second;
  64. for (Object::PropertiesMap::iterator piter = object->properties_map.begin();
  65. piter != object->properties_map.end(); ++piter) {
  66. PropertySet* properties = piter->second;
  67. delete properties;
  68. }
  69. delete object;
  70. }
  71. }
  72. void ObjectManager::RegisterInterface(const std::string& interface_name,
  73. Interface* interface) {
  74. interface_map_[interface_name] = interface;
  75. }
  76. void ObjectManager::UnregisterInterface(const std::string& interface_name) {
  77. InterfaceMap::iterator iter = interface_map_.find(interface_name);
  78. if (iter != interface_map_.end())
  79. interface_map_.erase(iter);
  80. }
  81. bool ObjectManager::IsInterfaceRegisteredForTesting(
  82. const std::string& interface_name) const {
  83. return interface_map_.count(interface_name);
  84. }
  85. std::vector<ObjectPath> ObjectManager::GetObjects() {
  86. std::vector<ObjectPath> object_paths;
  87. for (ObjectMap::iterator iter = object_map_.begin();
  88. iter != object_map_.end(); ++iter)
  89. object_paths.push_back(iter->first);
  90. return object_paths;
  91. }
  92. std::vector<ObjectPath> ObjectManager::GetObjectsWithInterface(
  93. const std::string& interface_name) {
  94. std::vector<ObjectPath> object_paths;
  95. for (ObjectMap::iterator oiter = object_map_.begin();
  96. oiter != object_map_.end(); ++oiter) {
  97. Object* object = oiter->second;
  98. Object::PropertiesMap::iterator piter =
  99. object->properties_map.find(interface_name);
  100. if (piter != object->properties_map.end())
  101. object_paths.push_back(oiter->first);
  102. }
  103. return object_paths;
  104. }
  105. ObjectProxy* ObjectManager::GetObjectProxy(const ObjectPath& object_path) {
  106. ObjectMap::iterator iter = object_map_.find(object_path);
  107. if (iter == object_map_.end())
  108. return nullptr;
  109. Object* object = iter->second;
  110. return object->object_proxy;
  111. }
  112. PropertySet* ObjectManager::GetProperties(const ObjectPath& object_path,
  113. const std::string& interface_name) {
  114. ObjectMap::iterator iter = object_map_.find(object_path);
  115. if (iter == object_map_.end())
  116. return nullptr;
  117. Object* object = iter->second;
  118. Object::PropertiesMap::iterator piter =
  119. object->properties_map.find(interface_name);
  120. if (piter == object->properties_map.end())
  121. return nullptr;
  122. return piter->second;
  123. }
  124. void ObjectManager::GetManagedObjects() {
  125. MethodCall method_call(kObjectManagerInterface,
  126. kObjectManagerGetManagedObjects);
  127. object_proxy_->CallMethod(&method_call, ObjectProxy::TIMEOUT_USE_DEFAULT,
  128. base::BindOnce(&ObjectManager::OnGetManagedObjects,
  129. weak_ptr_factory_.GetWeakPtr()));
  130. }
  131. void ObjectManager::CleanUp() {
  132. DCHECK(bus_);
  133. bus_->AssertOnDBusThread();
  134. DCHECK(!cleanup_called_);
  135. cleanup_called_ = true;
  136. if (!setup_success_)
  137. return;
  138. bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
  139. ScopedDBusError error;
  140. bus_->RemoveMatch(match_rule_, error.get());
  141. if (error.is_set())
  142. LOG(ERROR) << "Failed to remove match rule: " << match_rule_;
  143. match_rule_.clear();
  144. }
  145. bool ObjectManager::SetupMatchRuleAndFilter() {
  146. DCHECK(bus_);
  147. DCHECK(!setup_success_);
  148. bus_->AssertOnDBusThread();
  149. if (cleanup_called_)
  150. return false;
  151. if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
  152. return false;
  153. // Try to get |service_name_owner_| from dbus if we haven't received any
  154. // NameOwnerChanged signals.
  155. if (service_name_owner_.empty()) {
  156. service_name_owner_ =
  157. bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
  158. }
  159. const std::string match_rule =
  160. base::StringPrintf(
  161. "type='signal', sender='%s', interface='%s', member='%s'",
  162. service_name_.c_str(),
  163. kPropertiesInterface,
  164. kPropertiesChanged);
  165. bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this);
  166. ScopedDBusError error;
  167. bus_->AddMatch(match_rule, error.get());
  168. if (error.is_set()) {
  169. LOG(ERROR) << "ObjectManager failed to add match rule \"" << match_rule
  170. << "\". Got " << error.name() << ": " << error.message();
  171. bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
  172. return false;
  173. }
  174. match_rule_ = match_rule;
  175. setup_success_ = true;
  176. return true;
  177. }
  178. void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success) {
  179. if (!success) {
  180. LOG(WARNING) << service_name_ << " " << object_path_.value()
  181. << ": Failed to set up match rule.";
  182. return;
  183. }
  184. DCHECK(bus_);
  185. DCHECK(object_proxy_);
  186. DCHECK(setup_success_);
  187. bus_->AssertOnOriginThread();
  188. // |object_proxy_| is no longer valid if the Bus was shut down before this
  189. // call. Don't initiate any other action from the origin thread.
  190. if (cleanup_called_)
  191. return;
  192. object_proxy_->ConnectToSignal(
  193. kObjectManagerInterface, kObjectManagerInterfacesAdded,
  194. base::BindRepeating(&ObjectManager::InterfacesAddedReceived,
  195. weak_ptr_factory_.GetWeakPtr()),
  196. base::BindOnce(&ObjectManager::InterfacesAddedConnected,
  197. weak_ptr_factory_.GetWeakPtr()));
  198. object_proxy_->ConnectToSignal(
  199. kObjectManagerInterface, kObjectManagerInterfacesRemoved,
  200. base::BindRepeating(&ObjectManager::InterfacesRemovedReceived,
  201. weak_ptr_factory_.GetWeakPtr()),
  202. base::BindOnce(&ObjectManager::InterfacesRemovedConnected,
  203. weak_ptr_factory_.GetWeakPtr()));
  204. if (!service_name_owner_.empty())
  205. GetManagedObjects();
  206. }
  207. // static
  208. DBusHandlerResult ObjectManager::HandleMessageThunk(DBusConnection* connection,
  209. DBusMessage* raw_message,
  210. void* user_data) {
  211. ObjectManager* self = reinterpret_cast<ObjectManager*>(user_data);
  212. return self->HandleMessage(connection, raw_message);
  213. }
  214. DBusHandlerResult ObjectManager::HandleMessage(DBusConnection* connection,
  215. DBusMessage* raw_message) {
  216. DCHECK(bus_);
  217. bus_->AssertOnDBusThread();
  218. // Handle the message only if it is a signal.
  219. // Note that the match rule in SetupMatchRuleAndFilter() is configured to
  220. // only accept signals, but we check here just in case.
  221. if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
  222. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  223. // raw_message will be unrefed on exit of the function. Increment the
  224. // reference so we can use it in Signal.
  225. dbus_message_ref(raw_message);
  226. std::unique_ptr<Signal> signal(Signal::FromRawMessage(raw_message));
  227. const std::string interface = signal->GetInterface();
  228. const std::string member = signal->GetMember();
  229. statistics::AddReceivedSignal(service_name_, interface, member);
  230. // Handle the signal only if it is PropertiesChanged.
  231. // Note that the match rule in SetupMatchRuleAndFilter() is configured to
  232. // only accept PropertiesChanged signals, but we check here just in case.
  233. const std::string absolute_signal_name =
  234. GetAbsoluteMemberName(interface, member);
  235. const std::string properties_changed_signal_name =
  236. GetAbsoluteMemberName(kPropertiesInterface, kPropertiesChanged);
  237. if (absolute_signal_name != properties_changed_signal_name)
  238. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  239. VLOG(1) << "Signal received: " << signal->ToString();
  240. // Handle the signal only if it is from the service that the ObjectManager
  241. // instance is interested in.
  242. // Note that the match rule in SetupMatchRuleAndFilter() is configured to
  243. // only accept messages from the service name of our interest. However, the
  244. // service='...' filter does not work as intended. See crbug.com/507206#14
  245. // and #15 for details, hence it's necessary to check the sender here.
  246. std::string sender = signal->GetSender();
  247. if (service_name_owner_ != sender)
  248. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  249. const ObjectPath path = signal->GetPath();
  250. if (bus_->HasDBusThread()) {
  251. // Post a task to run the method in the origin thread. Transfer ownership of
  252. // |signal| to NotifyPropertiesChanged, which will handle the clean up.
  253. Signal* released_signal = signal.release();
  254. bus_->GetOriginTaskRunner()->PostTask(
  255. FROM_HERE, base::BindOnce(&ObjectManager::NotifyPropertiesChanged, this,
  256. path, released_signal));
  257. } else {
  258. // If the D-Bus thread is not used, just call the callback on the
  259. // current thread. Transfer the ownership of |signal| to
  260. // NotifyPropertiesChanged.
  261. NotifyPropertiesChanged(path, signal.release());
  262. }
  263. // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
  264. // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
  265. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  266. }
  267. void ObjectManager::NotifyPropertiesChanged(
  268. const dbus::ObjectPath object_path,
  269. Signal* signal) {
  270. DCHECK(bus_);
  271. bus_->AssertOnOriginThread();
  272. NotifyPropertiesChangedHelper(object_path, signal);
  273. // Delete the message on the D-Bus thread. See comments in HandleMessage.
  274. bus_->GetDBusTaskRunner()->PostTask(
  275. FROM_HERE, base::BindOnce(&base::DeletePointer<Signal>, signal));
  276. }
  277. void ObjectManager::NotifyPropertiesChangedHelper(
  278. const dbus::ObjectPath object_path,
  279. Signal* signal) {
  280. DCHECK(bus_);
  281. bus_->AssertOnOriginThread();
  282. MessageReader reader(signal);
  283. std::string interface;
  284. if (!reader.PopString(&interface)) {
  285. LOG(WARNING) << "Property changed signal has wrong parameters: "
  286. << "expected interface name: " << signal->ToString();
  287. return;
  288. }
  289. PropertySet* properties = GetProperties(object_path, interface);
  290. if (properties)
  291. properties->ChangedReceived(signal);
  292. }
  293. void ObjectManager::OnGetManagedObjects(Response* response) {
  294. if (response != nullptr) {
  295. MessageReader reader(response);
  296. MessageReader array_reader(nullptr);
  297. if (!reader.PopArray(&array_reader))
  298. return;
  299. while (array_reader.HasMoreData()) {
  300. MessageReader dict_entry_reader(nullptr);
  301. ObjectPath object_path;
  302. if (!array_reader.PopDictEntry(&dict_entry_reader) ||
  303. !dict_entry_reader.PopObjectPath(&object_path))
  304. continue;
  305. UpdateObject(object_path, &dict_entry_reader);
  306. }
  307. } else {
  308. LOG(WARNING) << service_name_ << " " << object_path_.value()
  309. << ": Failed to get managed objects";
  310. }
  311. }
  312. void ObjectManager::InterfacesAddedReceived(Signal* signal) {
  313. DCHECK(signal);
  314. MessageReader reader(signal);
  315. ObjectPath object_path;
  316. if (!reader.PopObjectPath(&object_path)) {
  317. LOG(WARNING) << service_name_ << " " << object_path_.value()
  318. << ": InterfacesAdded signal has incorrect parameters: "
  319. << signal->ToString();
  320. return;
  321. }
  322. UpdateObject(object_path, &reader);
  323. }
  324. void ObjectManager::InterfacesAddedConnected(const std::string& interface_name,
  325. const std::string& signal_name,
  326. bool success) {
  327. LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
  328. << ": Failed to connect to InterfacesAdded signal.";
  329. }
  330. void ObjectManager::InterfacesRemovedReceived(Signal* signal) {
  331. DCHECK(signal);
  332. MessageReader reader(signal);
  333. ObjectPath object_path;
  334. std::vector<std::string> interface_names;
  335. if (!reader.PopObjectPath(&object_path) ||
  336. !reader.PopArrayOfStrings(&interface_names)) {
  337. LOG(WARNING) << service_name_ << " " << object_path_.value()
  338. << ": InterfacesRemoved signal has incorrect parameters: "
  339. << signal->ToString();
  340. return;
  341. }
  342. for (size_t i = 0; i < interface_names.size(); ++i)
  343. RemoveInterface(object_path, interface_names[i]);
  344. }
  345. void ObjectManager::InterfacesRemovedConnected(
  346. const std::string& interface_name,
  347. const std::string& signal_name,
  348. bool success) {
  349. LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
  350. << ": Failed to connect to "
  351. << "InterfacesRemoved signal.";
  352. }
  353. void ObjectManager::UpdateObject(const ObjectPath& object_path,
  354. MessageReader* reader) {
  355. DCHECK(reader);
  356. MessageReader array_reader(nullptr);
  357. if (!reader->PopArray(&array_reader))
  358. return;
  359. while (array_reader.HasMoreData()) {
  360. MessageReader dict_entry_reader(nullptr);
  361. std::string interface_name;
  362. if (!array_reader.PopDictEntry(&dict_entry_reader) ||
  363. !dict_entry_reader.PopString(&interface_name))
  364. continue;
  365. AddInterface(object_path, interface_name, &dict_entry_reader);
  366. }
  367. }
  368. void ObjectManager::AddInterface(const ObjectPath& object_path,
  369. const std::string& interface_name,
  370. MessageReader* reader) {
  371. InterfaceMap::iterator iiter = interface_map_.find(interface_name);
  372. if (iiter == interface_map_.end())
  373. return;
  374. Interface* interface = iiter->second;
  375. ObjectMap::iterator oiter = object_map_.find(object_path);
  376. Object* object;
  377. if (oiter == object_map_.end()) {
  378. object = object_map_[object_path] = new Object;
  379. object->object_proxy = bus_->GetObjectProxy(service_name_, object_path);
  380. } else
  381. object = oiter->second;
  382. Object::PropertiesMap::iterator piter =
  383. object->properties_map.find(interface_name);
  384. PropertySet* property_set;
  385. const bool interface_added = (piter == object->properties_map.end());
  386. if (interface_added) {
  387. property_set = object->properties_map[interface_name] =
  388. interface->CreateProperties(object->object_proxy,
  389. object_path, interface_name);
  390. } else
  391. property_set = piter->second;
  392. property_set->UpdatePropertiesFromReader(reader);
  393. if (interface_added)
  394. interface->ObjectAdded(object_path, interface_name);
  395. }
  396. void ObjectManager::RemoveInterface(const ObjectPath& object_path,
  397. const std::string& interface_name) {
  398. ObjectMap::iterator oiter = object_map_.find(object_path);
  399. if (oiter == object_map_.end())
  400. return;
  401. Object* object = oiter->second;
  402. Object::PropertiesMap::iterator piter =
  403. object->properties_map.find(interface_name);
  404. if (piter == object->properties_map.end())
  405. return;
  406. // Inform the interface before removing the properties structure or object
  407. // in case it needs details from them to make its own decisions.
  408. InterfaceMap::iterator iiter = interface_map_.find(interface_name);
  409. if (iiter != interface_map_.end()) {
  410. Interface* interface = iiter->second;
  411. interface->ObjectRemoved(object_path, interface_name);
  412. }
  413. delete piter->second;
  414. object->properties_map.erase(piter);
  415. if (object->properties_map.empty()) {
  416. object_map_.erase(oiter);
  417. delete object;
  418. }
  419. }
  420. void ObjectManager::UpdateServiceNameOwner(const std::string& new_owner) {
  421. bus_->AssertOnDBusThread();
  422. service_name_owner_ = new_owner;
  423. }
  424. void ObjectManager::NameOwnerChanged(const std::string& old_owner,
  425. const std::string& new_owner) {
  426. bus_->AssertOnOriginThread();
  427. bus_->GetDBusTaskRunner()->PostTask(
  428. FROM_HERE,
  429. base::BindOnce(&ObjectManager::UpdateServiceNameOwner, this, new_owner));
  430. if (!old_owner.empty()) {
  431. ObjectMap::iterator iter = object_map_.begin();
  432. while (iter != object_map_.end()) {
  433. ObjectMap::iterator tmp = iter;
  434. ++iter;
  435. // PropertiesMap is mutated by RemoveInterface, and also Object is
  436. // destroyed; easier to collect the object path and interface names
  437. // and remove them safely.
  438. const dbus::ObjectPath object_path = tmp->first;
  439. Object* object = tmp->second;
  440. std::vector<std::string> interfaces;
  441. for (Object::PropertiesMap::iterator piter =
  442. object->properties_map.begin();
  443. piter != object->properties_map.end(); ++piter)
  444. interfaces.push_back(piter->first);
  445. for (std::vector<std::string>::iterator iiter = interfaces.begin();
  446. iiter != interfaces.end(); ++iiter)
  447. RemoveInterface(object_path, *iiter);
  448. }
  449. }
  450. if (!new_owner.empty())
  451. GetManagedObjects();
  452. }
  453. } // namespace dbus