dbus: allow unregistering of exported objects
Not all objects are permanent, some are transient and if we ever
re-use the object path, we want a new instance of the exported object
to be created rather than re-use an existing one.
BUG=chromium-os:21320
TEST=dbus_unittests and included change to agent service provider
Change-Id: I09882bbe2f70356182ac301c4260473051333424
Review URL: http://codereview.chromium.org/9691025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126527 0039d316-1c4b-4281-b951-d872f2087c98
CrOS-Libchrome-Original-Commit: d7361fdcda06ab78b9777c923790e0c7b71b0a06
diff --git a/dbus/bus.cc b/dbus/bus.cc
index 9d4a436..91ba252 100644
--- a/dbus/bus.cc
+++ b/dbus/bus.cc
@@ -250,6 +250,35 @@
return exported_object.get();
}
+void Bus::UnregisterExportedObject(const ObjectPath& object_path) {
+ AssertOnOriginThread();
+
+ // Remove the registered object from the table first, to allow a new
+ // GetExportedObject() call to return a new object, rather than this one.
+ ExportedObjectTable::iterator iter = exported_object_table_.find(object_path);
+ if (iter == exported_object_table_.end())
+ return;
+
+ scoped_refptr<ExportedObject> exported_object = iter->second;
+ exported_object_table_.erase(iter);
+
+ // Post the task to perform the final unregistration to the D-Bus thread.
+ // Since the registration also happens on the D-Bus thread in
+ // TryRegisterObjectPath(), and the message loop proxy we post to is a
+ // MessageLoopProxy which inherits from SequencedTaskRunner, there is a
+ // guarantee that this will happen before any future registration call.
+ PostTaskToDBusThread(FROM_HERE, base::Bind(
+ &Bus::UnregisterExportedObjectInternal,
+ this, exported_object));
+}
+
+void Bus::UnregisterExportedObjectInternal(
+ scoped_refptr<dbus::ExportedObject> exported_object) {
+ AssertOnDBusThread();
+
+ exported_object->Unregister();
+}
+
bool Bus::Connect() {
// dbus_bus_get_private() and dbus_bus_get() are blocking calls.
AssertOnDBusThread();
diff --git a/dbus/bus.h b/dbus/bus.h
index 2684dcd..8e3ceea 100644
--- a/dbus/bus.h
+++ b/dbus/bus.h
@@ -226,6 +226,15 @@
// Must be called in the origin thread.
virtual ExportedObject* GetExportedObject(const ObjectPath& object_path);
+ // Unregisters the exported object for the given object path |object_path|.
+ //
+ // Getting an exported object for the same object path after this call
+ // will return a new object, method calls on any remaining copies of the
+ // previous object will not be called.
+ //
+ // Must be called in the origin thread.
+ virtual void UnregisterExportedObject(const ObjectPath& object_path);
+
// Shuts down the bus and blocks until it's done. More specifically, this
// function does the following:
//
@@ -420,6 +429,10 @@
private:
friend class base::RefCountedThreadSafe<Bus>;
+ // Helper function used for UnregisterExportedObject().
+ void UnregisterExportedObjectInternal(
+ scoped_refptr<dbus::ExportedObject> exported_object);
+
// Helper function used for ShutdownOnDBusThreadAndBlock().
void ShutdownOnDBusThreadAndBlockInternal();
diff --git a/dbus/bus_unittest.cc b/dbus/bus_unittest.cc
index 4e7e8fd..4011556 100644
--- a/dbus/bus_unittest.cc
+++ b/dbus/bus_unittest.cc
@@ -108,6 +108,37 @@
bus->ShutdownAndBlock();
}
+TEST(BusTest, UnregisterExportedObject) {
+ // Start the D-Bus thread.
+ base::Thread::Options thread_options;
+ thread_options.message_loop_type = MessageLoop::TYPE_IO;
+ base::Thread dbus_thread("D-Bus thread");
+ dbus_thread.StartWithOptions(thread_options);
+
+ // Create the bus.
+ dbus::Bus::Options options;
+ options.dbus_thread_message_loop_proxy = dbus_thread.message_loop_proxy();
+ scoped_refptr<dbus::Bus> bus = new dbus::Bus(options);
+ ASSERT_FALSE(bus->shutdown_completed());
+
+ dbus::ExportedObject* object_proxy1 =
+ bus->GetExportedObject(dbus::ObjectPath("/org/chromium/TestObject"));
+ ASSERT_TRUE(object_proxy1);
+
+ bus->UnregisterExportedObject(dbus::ObjectPath("/org/chromium/TestObject"));
+
+ // This should return a new object.
+ dbus::ExportedObject* object_proxy2 =
+ bus->GetExportedObject(dbus::ObjectPath("/org/chromium/TestObject"));
+ ASSERT_TRUE(object_proxy2);
+ EXPECT_NE(object_proxy1, object_proxy2);
+
+ // Shut down synchronously.
+ bus->ShutdownOnDBusThreadAndBlock();
+ EXPECT_TRUE(bus->shutdown_completed());
+ dbus_thread.Stop();
+}
+
TEST(BusTest, ShutdownAndBlock) {
dbus::Bus::Options options;
scoped_refptr<dbus::Bus> bus = new dbus::Bus(options);