Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(682)

Side by Side Diff: dbus/object_manager.cc

Issue 510863002: dbus::ObjectManager: Add a match rule for properties before GetManagedObjects. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed comments by satorux@; added unit test. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "dbus/object_manager.h" 5 #include "dbus/object_manager.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/location.h"
8 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/task_runner_util.h"
9 #include "dbus/bus.h" 13 #include "dbus/bus.h"
14 #include "dbus/dbus_statistics.h"
10 #include "dbus/message.h" 15 #include "dbus/message.h"
11 #include "dbus/object_proxy.h" 16 #include "dbus/object_proxy.h"
12 #include "dbus/property.h" 17 #include "dbus/property.h"
18 #include "dbus/scoped_dbus_error.h"
13 19
14 namespace dbus { 20 namespace dbus {
15 21
22 namespace {
23
24 // TODO(armansito): Move this to a utils file so that it can be reused among
25 // ObjectManager and ObjectProxy.
26 // Gets the absolute signal name by concatenating the interface name and
27 // the signal name.
28 std::string GetAbsoluteSignalName(
29 const std::string& interface_name,
30 const std::string& signal_name) {
31 return interface_name + "." + signal_name;
32 }
33
34 } // namespace
35
16 ObjectManager::Object::Object() 36 ObjectManager::Object::Object()
17 : object_proxy(NULL) { 37 : object_proxy(NULL) {
18 } 38 }
19 39
20 ObjectManager::Object::~Object() { 40 ObjectManager::Object::~Object() {
21 } 41 }
22 42
23 ObjectManager::ObjectManager(Bus* bus, 43 ObjectManager::ObjectManager(Bus* bus,
24 const std::string& service_name, 44 const std::string& service_name,
25 const ObjectPath& object_path) 45 const ObjectPath& object_path)
26 : bus_(bus), 46 : bus_(bus),
27 service_name_(service_name), 47 service_name_(service_name),
28 object_path_(object_path), 48 object_path_(object_path),
49 setup_success_(false),
29 weak_ptr_factory_(this) { 50 weak_ptr_factory_(this) {
30 DVLOG(1) << "Creating ObjectManager for " << service_name_ 51 DVLOG(1) << "Creating ObjectManager for " << service_name_
31 << " " << object_path_.value(); 52 << " " << object_path_.value();
32
33 DCHECK(bus_); 53 DCHECK(bus_);
54 bus_->AssertOnOriginThread();
34 object_proxy_ = bus_->GetObjectProxy(service_name_, object_path_); 55 object_proxy_ = bus_->GetObjectProxy(service_name_, object_path_);
35 object_proxy_->SetNameOwnerChangedCallback( 56 object_proxy_->SetNameOwnerChangedCallback(
36 base::Bind(&ObjectManager::NameOwnerChanged, 57 base::Bind(&ObjectManager::NameOwnerChanged,
37 weak_ptr_factory_.GetWeakPtr())); 58 weak_ptr_factory_.GetWeakPtr()));
38 59
39 object_proxy_->ConnectToSignal( 60 // Set up a match rule and a filter function to handle PropertiesChanged
40 kObjectManagerInterface, 61 // signals from the service. This is important to avoid any race conditions
41 kObjectManagerInterfacesAdded, 62 // that might cause us to miss PropertiesChanged signals once all objects are
42 base::Bind(&ObjectManager::InterfacesAddedReceived, 63 // initialized via GetManagedObjects.
43 weak_ptr_factory_.GetWeakPtr()), 64 base::PostTaskAndReplyWithResult(
44 base::Bind(&ObjectManager::InterfacesAddedConnected, 65 bus_->GetDBusTaskRunner(),
45 weak_ptr_factory_.GetWeakPtr())); 66 FROM_HERE,
46 67 base::Bind(&ObjectManager::SetupMatchRuleAndFilter, this),
47 object_proxy_->ConnectToSignal( 68 base::Bind(&ObjectManager::OnSetupMatchRuleAndFilterComplete, this));
48 kObjectManagerInterface,
49 kObjectManagerInterfacesRemoved,
50 base::Bind(&ObjectManager::InterfacesRemovedReceived,
51 weak_ptr_factory_.GetWeakPtr()),
52 base::Bind(&ObjectManager::InterfacesRemovedConnected,
53 weak_ptr_factory_.GetWeakPtr()));
54
55 GetManagedObjects();
56 } 69 }
57 70
58 ObjectManager::~ObjectManager() { 71 ObjectManager::~ObjectManager() {
59 // Clean up Object structures 72 // Clean up Object structures
60 for (ObjectMap::iterator iter = object_map_.begin(); 73 for (ObjectMap::iterator iter = object_map_.begin();
61 iter != object_map_.end(); ++iter) { 74 iter != object_map_.end(); ++iter) {
62 Object* object = iter->second; 75 Object* object = iter->second;
63 76
64 for (Object::PropertiesMap::iterator piter = object->properties_map.begin(); 77 for (Object::PropertiesMap::iterator piter = object->properties_map.begin();
65 piter != object->properties_map.end(); ++piter) { 78 piter != object->properties_map.end(); ++piter) {
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 MethodCall method_call(kObjectManagerInterface, 150 MethodCall method_call(kObjectManagerInterface,
138 kObjectManagerGetManagedObjects); 151 kObjectManagerGetManagedObjects);
139 152
140 object_proxy_->CallMethod( 153 object_proxy_->CallMethod(
141 &method_call, 154 &method_call,
142 ObjectProxy::TIMEOUT_USE_DEFAULT, 155 ObjectProxy::TIMEOUT_USE_DEFAULT,
143 base::Bind(&ObjectManager::OnGetManagedObjects, 156 base::Bind(&ObjectManager::OnGetManagedObjects,
144 weak_ptr_factory_.GetWeakPtr())); 157 weak_ptr_factory_.GetWeakPtr()));
145 } 158 }
146 159
160 void ObjectManager::CleanUp() {
161 DCHECK(bus_);
162 bus_->AssertOnDBusThread();
163
164 if (!setup_success_)
165 return;
166
167 if (!bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this))
168 LOG(ERROR) << "Failed to remove filter function";
169
170 ScopedDBusError error;
171 bus_->RemoveMatch(match_rule_, error.get());
172 if (error.is_set())
173 LOG(ERROR) << "Failed to remove match rule: " << match_rule_;
174
175 match_rule_.clear();
176 }
177
178 void ObjectManager::InitializeObjects() {
179 DCHECK(bus_);
180 object_proxy_->ConnectToSignal(
181 kObjectManagerInterface,
182 kObjectManagerInterfacesAdded,
183 base::Bind(&ObjectManager::InterfacesAddedReceived,
184 weak_ptr_factory_.GetWeakPtr()),
185 base::Bind(&ObjectManager::InterfacesAddedConnected,
186 weak_ptr_factory_.GetWeakPtr()));
187
188 object_proxy_->ConnectToSignal(
189 kObjectManagerInterface,
190 kObjectManagerInterfacesRemoved,
191 base::Bind(&ObjectManager::InterfacesRemovedReceived,
192 weak_ptr_factory_.GetWeakPtr()),
193 base::Bind(&ObjectManager::InterfacesRemovedConnected,
194 weak_ptr_factory_.GetWeakPtr()));
195
196 GetManagedObjects();
197 }
198
199 bool ObjectManager::SetupMatchRuleAndFilter() {
200 DCHECK(bus_);
201 DCHECK(!setup_success_);
202 bus_->AssertOnDBusThread();
203
204 if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
205 return false;
206
207 service_name_owner_ =
208 bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
209
210 const std::string match_rule =
211 base::StringPrintf(
212 "type='signal', sender='%s', interface='%s', member='%s'",
213 service_name_.c_str(),
214 kPropertiesInterface,
215 kPropertiesChanged);
216
217 if (!bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this)) {
218 LOG(ERROR) << "ObjectManager failed to add filter function";
219 return false;
220 }
221
222 ScopedDBusError error;
223 bus_->AddMatch(match_rule, error.get());
224 if (error.is_set()) {
225 LOG(ERROR) << "ObjectManager failed to add match rule \"" << match_rule
226 << "\". Got " << error.name() << ": " << error.message();
227 bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
228 return false;
229 }
230
231 match_rule_ = match_rule;
232 setup_success_ = true;
233
234 return true;
235 }
236
237 void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success) {
238 LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
239 << ": Failed to set up match rule.";
240 if (success)
241 InitializeObjects();
242 }
243
244 // static
245 DBusHandlerResult ObjectManager::HandleMessageThunk(DBusConnection* connection,
246 DBusMessage* raw_message,
247 void* user_data) {
248 ObjectManager* self = reinterpret_cast<ObjectManager*>(user_data);
249 return self->HandleMessage(connection, raw_message);
250 }
251
252 DBusHandlerResult ObjectManager::HandleMessage(DBusConnection* connection,
253 DBusMessage* raw_message) {
254 DCHECK(bus_);
255 bus_->AssertOnDBusThread();
256
257 if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
258 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
259
260 // raw_message will be unrefed on exit of the function. Increment the
261 // reference so we can use it in Signal.
262 dbus_message_ref(raw_message);
263 scoped_ptr<Signal> signal(
264 Signal::FromRawMessage(raw_message));
265
266 const std::string interface = signal->GetInterface();
267 const std::string member = signal->GetMember();
268
269 statistics::AddReceivedSignal(service_name_, interface, member);
270
271 // Only handle the PropertiesChanged signal.
272 const std::string absolute_signal_name =
273 GetAbsoluteSignalName(interface, member);
274 const std::string properties_changed_signal_name =
275 GetAbsoluteSignalName(kPropertiesInterface, kPropertiesChanged);
276 if (absolute_signal_name != properties_changed_signal_name)
277 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
278
279 VLOG(1) << "Signal received: " << signal->ToString();
280
281 // Make sure that the signal originated from the correct sender.
282 std::string sender = signal->GetSender();
283 if (service_name_owner_ != sender) {
284 LOG(ERROR) << "Rejecting a message from a wrong sender.";
285 UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
286 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
287 }
288
289 const ObjectPath path = signal->GetPath();
290
291 if (bus_->HasDBusThread()) {
292 // Post a task to run the method in the origin thread. Transfer ownership of
293 // |signal| to NotifyPropertiesChanged, which will handle the clean up.
294 Signal* released_signal = signal.release();
295 bus_->GetOriginTaskRunner()->PostTask(
296 FROM_HERE,
297 base::Bind(&ObjectManager::NotifyPropertiesChanged,
298 this, path,
299 released_signal));
300 } else {
301 // If the D-Bus thread is not used, just call the callback on the
302 // current thread. Transfer the ownership of |signal| to
303 // NotifyPropertiesChanged.
304 NotifyPropertiesChanged(path, signal.release());
305 }
306
307 // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
308 // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
309 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
310 }
311
312 void ObjectManager::NotifyPropertiesChanged(
313 const dbus::ObjectPath object_path,
314 Signal* signal) {
315 DCHECK(bus_);
316 bus_->AssertOnOriginThread();
317
318 NotifyPropertiesChangedHelper(object_path, signal);
319
320 // Delete the message on the D-Bus thread. See comments in HandleMessage.
321 bus_->GetDBusTaskRunner()->PostTask(
322 FROM_HERE,
323 base::Bind(&base::DeletePointer<Signal>, signal));
324 }
325
326 void ObjectManager::NotifyPropertiesChangedHelper(
327 const dbus::ObjectPath object_path,
328 Signal* signal) {
329 MessageReader reader(signal);
330 std::string interface;
331 if (!reader.PopString(&interface)) {
332 LOG(WARNING) << "Property changed signal has wrong parameters: "
333 << "expected interface name: " << signal->ToString();
334 return;
335 }
336
337 PropertySet* properties = GetProperties(object_path, interface);
338 if (properties)
339 properties->ChangedReceived(signal);
340 }
341
147 void ObjectManager::OnGetManagedObjects(Response* response) { 342 void ObjectManager::OnGetManagedObjects(Response* response) {
148 if (response != NULL) { 343 if (response != NULL) {
149 MessageReader reader(response); 344 MessageReader reader(response);
150 MessageReader array_reader(NULL); 345 MessageReader array_reader(NULL);
151 if (!reader.PopArray(&array_reader)) 346 if (!reader.PopArray(&array_reader))
152 return; 347 return;
153 348
154 while (array_reader.HasMoreData()) { 349 while (array_reader.HasMoreData()) {
155 MessageReader dict_entry_reader(NULL); 350 MessageReader dict_entry_reader(NULL);
156 ObjectPath object_path; 351 ObjectPath object_path;
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 object = oiter->second; 445 object = oiter->second;
251 446
252 Object::PropertiesMap::iterator piter = 447 Object::PropertiesMap::iterator piter =
253 object->properties_map.find(interface_name); 448 object->properties_map.find(interface_name);
254 PropertySet* property_set; 449 PropertySet* property_set;
255 const bool interface_added = (piter == object->properties_map.end()); 450 const bool interface_added = (piter == object->properties_map.end());
256 if (interface_added) { 451 if (interface_added) {
257 property_set = object->properties_map[interface_name] = 452 property_set = object->properties_map[interface_name] =
258 interface->CreateProperties(object->object_proxy, 453 interface->CreateProperties(object->object_proxy,
259 object_path, interface_name); 454 object_path, interface_name);
260 property_set->ConnectSignals();
261 } else 455 } else
262 property_set = piter->second; 456 property_set = piter->second;
263 457
264 property_set->UpdatePropertiesFromReader(reader); 458 property_set->UpdatePropertiesFromReader(reader);
265 459
266 if (interface_added) 460 if (interface_added)
267 interface->ObjectAdded(object_path, interface_name); 461 interface->ObjectAdded(object_path, interface_name);
268 } 462 }
269 463
270 void ObjectManager::RemoveInterface(const ObjectPath& object_path, 464 void ObjectManager::RemoveInterface(const ObjectPath& object_path,
(...skipping 19 matching lines...) Expand all
290 object->properties_map.erase(piter); 484 object->properties_map.erase(piter);
291 485
292 if (object->properties_map.empty()) { 486 if (object->properties_map.empty()) {
293 object_map_.erase(oiter); 487 object_map_.erase(oiter);
294 delete object; 488 delete object;
295 } 489 }
296 } 490 }
297 491
298 void ObjectManager::NameOwnerChanged(const std::string& old_owner, 492 void ObjectManager::NameOwnerChanged(const std::string& old_owner,
299 const std::string& new_owner) { 493 const std::string& new_owner) {
494 service_name_owner_ = new_owner;
495
300 if (!old_owner.empty()) { 496 if (!old_owner.empty()) {
301 ObjectMap::iterator iter = object_map_.begin(); 497 ObjectMap::iterator iter = object_map_.begin();
302 while (iter != object_map_.end()) { 498 while (iter != object_map_.end()) {
303 ObjectMap::iterator tmp = iter; 499 ObjectMap::iterator tmp = iter;
304 ++iter; 500 ++iter;
305 501
306 // PropertiesMap is mutated by RemoveInterface, and also Object is 502 // PropertiesMap is mutated by RemoveInterface, and also Object is
307 // destroyed; easier to collect the object path and interface names 503 // destroyed; easier to collect the object path and interface names
308 // and remove them safely. 504 // and remove them safely.
309 const dbus::ObjectPath object_path = tmp->first; 505 const dbus::ObjectPath object_path = tmp->first;
(...skipping 10 matching lines...) Expand all
320 RemoveInterface(object_path, *iiter); 516 RemoveInterface(object_path, *iiter);
321 } 517 }
322 518
323 } 519 }
324 520
325 if (!new_owner.empty()) 521 if (!new_owner.empty())
326 GetManagedObjects(); 522 GetManagedObjects();
327 } 523 }
328 524
329 } // namespace dbus 525 } // namespace dbus
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698