buffet: Add ObjectManager interface to /org/chromium/Buffet
BUG=chromium:359190
TEST=`buffet_client GetManagedObjects` returns
message_type: MESSAGE_METHOD_RETURN
destination: :1.35
sender: :1.31
signature: a{oa{sa{sv}}}
serial: 10
reply_serial: 3
array [
dict entry {
object_path "/org/chromium/Buffet/Manager"
array [
dict entry {
string "org.chromium.Buffet.Manager"
array [
dict entry {
string "State"
variant string "{}"
}
]
}
]
}
]
Done.
Change-Id: I2bbcc9a3f71c7ec6ab76cb4600dad7efe1a8bb0a
Reviewed-on: https://chromium-review.googlesource.com/198963
Reviewed-by: Chris Sosa <sosa@chromium.org>
Commit-Queue: Christopher Wiley <wiley@chromium.org>
Tested-by: Christopher Wiley <wiley@chromium.org>
Reviewed-by: Ilja Friedel <ihf@chromium.org>
diff --git a/buffet/async_event_sequencer.cc b/buffet/async_event_sequencer.cc
index bf08d14..1dca62c 100644
--- a/buffet/async_event_sequencer.cc
+++ b/buffet/async_event_sequencer.cc
@@ -40,6 +40,16 @@
PossiblyRunCompletionActions();
}
+namespace {
+void IgnoreSuccess(const AsyncEventSequencer::CompletionTask& task,
+ bool /*success*/) { task.Run(); }
+} // namespace
+
+AsyncEventSequencer::CompletionAction AsyncEventSequencer::WrapCompletionTask(
+ const CompletionTask& task) {
+ return base::Bind(&IgnoreSuccess, task);
+}
+
void AsyncEventSequencer::HandleFinish(int registration_number,
const std::string& error_message,
bool failure_is_fatal, bool success) {
diff --git a/buffet/async_event_sequencer.h b/buffet/async_event_sequencer.h
index ab5bc1a..96adad7 100644
--- a/buffet/async_event_sequencer.h
+++ b/buffet/async_event_sequencer.h
@@ -41,24 +41,32 @@
const std::string& method_name,
bool success)> ExportHandler;
typedef base::Callback<void(bool all_succeeded)> CompletionAction;
+ typedef base::Callback<void(void)> CompletionTask;
AsyncEventSequencer();
+
// Get a Finished handler callback. Each callback is "unique" in the sense
// that subsequent calls to GetHandler() will create new handlers
// which will need to be called before completion actions are run.
Handler GetHandler(const std::string& descriptive_message,
bool failure_is_fatal);
+
// Like GetHandler except with a signature tailored to
// ExportedObject's ExportMethod callback requirements. Will also assert
// that the passed interface/method names from ExportedObject are correct.
ExportHandler GetExportHandler(
const std::string& interface_name, const std::string& method_name,
const std::string& descriptive_message, bool failure_is_fatal);
+
// Once all handlers obtained via GetHandler have run,
// we'll run each CompletionAction, then discard our references.
// No more handlers may be obtained after this call.
void OnAllTasksCompletedCall(std::vector<CompletionAction> actions);
+ // Wrap a CompletionTask with a function that discards the result.
+ // This CompletionTask retains no references to the AsyncEventSequencer.
+ CompletionAction WrapCompletionTask(const CompletionTask& task);
+
private:
// We'll partially bind this function before giving it back via
// GetHandler. Note that the returned callbacks have
diff --git a/buffet/buffet_client.cc b/buffet/buffet_client.cc
index 34eb89f..a763e42 100644
--- a/buffet/buffet_client.cc
+++ b/buffet/buffet_client.cc
@@ -14,6 +14,7 @@
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_proxy.h>
+#include <dbus/object_manager.h>
#include <dbus/values_util.h>
#include "buffet/dbus_constants.h"
@@ -34,6 +35,7 @@
std::cerr << " " << kManagerFinishRegisterDevice
<< " device_id" << std::endl;
std::cerr << " " << kManagerUpdateStateMethod << std::endl;
+ std::cerr << " " << dbus::kObjectManagerGetManagedObjects << std::endl;
}
class BuffetHelperProxy {
@@ -45,6 +47,9 @@
manager_proxy_ = bus_->GetObjectProxy(
kServiceName,
dbus::ObjectPath(kManagerServicePath));
+ root_proxy_ = bus_->GetObjectProxy(
+ kServiceName,
+ dbus::ObjectPath(kRootServicePath));
return EX_OK;
}
@@ -226,9 +231,29 @@
return EX_OK;
}
+ int CallRootGetManagedObjects(const CommandLine::StringVector& args) {
+ if (!args.empty()) {
+ std::cerr << "Invalid number of arguments for "
+ << dbus::kObjectManagerGetManagedObjects << std::endl;
+ usage();
+ return EX_USAGE;
+ }
+ dbus::MethodCall method_call(
+ dbus::kObjectManagerInterface, dbus::kObjectManagerGetManagedObjects);
+ scoped_ptr<dbus::Response> response(
+ root_proxy_->CallMethodAndBlock(&method_call, default_timeout_ms));
+ if (!response) {
+ std::cout << "Failed to receive a response." << std::endl;
+ return EX_UNAVAILABLE;
+ }
+ std::cout << response->ToString() << std::endl;
+ return EX_OK;
+ }
+
private:
scoped_refptr<dbus::Bus> bus_;
dbus::ObjectProxy* manager_proxy_{nullptr}; // NOLINT - initializer list
+ dbus::ObjectProxy* root_proxy_{nullptr}; // NOLINT - initializer list
};
} // namespace
@@ -270,6 +295,8 @@
} else if (command.compare(kManagerUpdateStateMethod) == 0 ||
command.compare("us") == 0) {
err = helper.CallManagerUpdateState(args);
+ } else if (command.compare(dbus::kObjectManagerGetManagedObjects) == 0) {
+ err = helper.CallRootGetManagedObjects(args);
} else {
std::cerr << "Unknown command: " << command << std::endl;
usage();
diff --git a/buffet/exported_object_manager.cc b/buffet/exported_object_manager.cc
index 6458128..c1403ad 100644
--- a/buffet/exported_object_manager.cc
+++ b/buffet/exported_object_manager.cc
@@ -12,10 +12,9 @@
namespace dbus_utils {
-ExportedObjectManager::ExportedObjectManager(dbus::Bus* bus,
+ExportedObjectManager::ExportedObjectManager(scoped_refptr<dbus::Bus> bus,
const dbus::ObjectPath& path)
- : bus_(bus), exported_object_(bus->GetExportedObject(path)),
- weak_ptr_factory_(this) {}
+ : bus_(bus), exported_object_(bus->GetExportedObject(path)) {}
void ExportedObjectManager::Init(const OnInitFinish& cb) {
bus_->AssertOnOriginThread();
@@ -25,12 +24,13 @@
dbus::kObjectManagerInterface,
dbus::kObjectManagerGetManagedObjects,
base::Bind(&ExportedObjectManager::HandleGetManagedObjects,
- weak_ptr_factory_.GetWeakPtr()),
+ AsWeakPtr()),
sequencer->GetExportHandler(
dbus::kObjectManagerInterface,
dbus::kObjectManagerGetManagedObjects,
"Failed exporting GetManagedObjects method of ObjectManager",
false));
+ sequencer->OnAllTasksCompletedCall({cb});
}
void ExportedObjectManager::ClaimInterface(
diff --git a/buffet/exported_object_manager.h b/buffet/exported_object_manager.h
index e1d8884..d483db0 100644
--- a/buffet/exported_object_manager.h
+++ b/buffet/exported_object_manager.h
@@ -69,14 +69,16 @@
// Properties my_properties_;
// ExampleObjectManager* object_manager_;
// };
-class ExportedObjectManager {
+class ExportedObjectManager
+ : public base::SupportsWeakPtr<ExportedObjectManager> {
public:
// Writes a dictionary of property name to property value variants to writer.
typedef base::Callback<void(dbus::MessageWriter* writer)> PropertyWriter;
typedef base::Callback<void(bool success)> OnInitFinish;
typedef std::map<std::string, PropertyWriter> InterfaceProperties;
- ExportedObjectManager(dbus::Bus* bus, const dbus::ObjectPath& path);
+ ExportedObjectManager(scoped_refptr<dbus::Bus> bus,
+ const dbus::ObjectPath& path);
// Registers methods implementing the ObjectManager interface on the object
// exported on the path given in the constructor. Must be called on the
@@ -104,9 +106,6 @@
// Tracks all objects currently known to the ExportedObjectManager.
std::map<dbus::ObjectPath, InterfaceProperties> registered_objects_;
- // We're going to register DBus callbacks that will outlive ourselves.
- // These callbacks get scheduled on the origin thread.
- base::WeakPtrFactory<ExportedObjectManager> weak_ptr_factory_;
friend class ExportedObjectManagerTest;
DISALLOW_COPY_AND_ASSIGN(ExportedObjectManager);
};
diff --git a/buffet/exported_property_set.cc b/buffet/exported_property_set.cc
index ba6b2c7..b1b5633 100644
--- a/buffet/exported_property_set.cc
+++ b/buffet/exported_property_set.cc
@@ -51,7 +51,12 @@
sequencer->OnAllTasksCompletedCall({cb});
}
-ExportedPropertySet::~ExportedPropertySet() { }
+ExportedPropertySet::PropertyWriter ExportedPropertySet::GetPropertyWriter(
+ const std::string& interface) {
+ return base::Bind(&ExportedPropertySet::WritePropertiesDictToMessage,
+ weak_ptr_factory_.GetWeakPtr(),
+ interface);
+}
void ExportedPropertySet::RegisterProperty(
const std::string& interface_name,
diff --git a/buffet/exported_property_set.h b/buffet/exported_property_set.h
index 3d7abc5..405ed7d 100644
--- a/buffet/exported_property_set.h
+++ b/buffet/exported_property_set.h
@@ -95,9 +95,10 @@
class ExportedPropertySet {
public:
typedef base::Callback<void(bool success)> OnInitFinish;
+ typedef base::Callback<void(dbus::MessageWriter* writer)> PropertyWriter;
ExportedPropertySet(dbus::Bus* bus, const dbus::ObjectPath& path);
- virtual ~ExportedPropertySet();
+ virtual ~ExportedPropertySet() = default;
// Claims the method associated with the org.freedesktop.DBus.Properties
// interface. This needs to be done after all properties are initialized to
@@ -105,8 +106,11 @@
// are exported to the DBus object. |cb| will be called on the origin
// thread.
void Init(const OnInitFinish& cb);
- base::Callback<void(dbus::MessageWriter* writer)> GetPropertyWriter(
- const std::string& interface);
+
+ // Return a callback that knows how to write this property set's properties
+ // to a message. This writer retains a weak pointer to this, and must
+ // only be invoked on the same thread as the rest of ExportedPropertySet.
+ PropertyWriter GetPropertyWriter(const std::string& interface);
protected:
void RegisterProperty(const std::string& interface_name,
diff --git a/buffet/main.cc b/buffet/main.cc
index e48a1b0..43ba4ab 100644
--- a/buffet/main.cc
+++ b/buffet/main.cc
@@ -16,9 +16,12 @@
#include <sysexits.h>
#include "buffet/async_event_sequencer.h"
+#include "buffet/dbus_constants.h"
+#include "buffet/exported_object_manager.h"
#include "buffet/manager.h"
using buffet::dbus_utils::AsyncEventSequencer;
+using buffet::dbus_utils::ExportedObjectManager;
namespace {
@@ -87,7 +90,11 @@
void EnterMainLoop(base::MessageLoopForIO* message_loop,
scoped_refptr<dbus::Bus> bus) {
scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
- buffet::Manager manager(bus.get());
+ ExportedObjectManager object_manager(
+ bus, dbus::ObjectPath(buffet::dbus_constants::kRootServicePath));
+ buffet::Manager manager(bus, object_manager.AsWeakPtr());
+ object_manager.Init(
+ sequencer->GetHandler("ObjectManager.Init() failed.", true));
manager.Init(sequencer->GetHandler("Manager.Init() failed.", true));
sequencer->OnAllTasksCompletedCall(
{base::Bind(&TakeServiceOwnership, bus)});
diff --git a/buffet/manager.cc b/buffet/manager.cc
index 09985b3..3639803 100644
--- a/buffet/manager.cc
+++ b/buffet/manager.cc
@@ -18,18 +18,26 @@
#include "buffet/dbus_constants.h"
#include "buffet/dbus_utils.h"
#include "buffet/error.h"
+#include "buffet/exported_object_manager.h"
+using buffet::dbus_utils::AsyncEventSequencer;
using buffet::dbus_utils::GetBadArgsError;
using buffet::dbus_utils::GetDBusError;
namespace buffet {
-Manager::Manager(dbus::Bus* bus)
+Manager::Manager(
+ scoped_refptr<dbus::Bus> bus,
+ base::WeakPtr<dbus_utils::ExportedObjectManager> object_manager)
: bus_(bus),
exported_object_(bus->GetExportedObject(
- dbus::ObjectPath(dbus_constants::kManagerServicePath))) { }
+ dbus::ObjectPath(dbus_constants::kManagerServicePath))),
+ object_manager_(object_manager) { }
Manager::~Manager() {
+ object_manager_->ReleaseInterface(
+ dbus::ObjectPath(dbus_constants::kManagerServicePath),
+ dbus_constants::kManagerInterface);
// Prevent the properties object from making calls to the exported object.
properties_.reset(nullptr);
// Unregister ourselves from the Bus. This prevents the bus from calling
@@ -41,8 +49,8 @@
}
void Manager::Init(const OnInitFinish& cb) {
- scoped_refptr<dbus_utils::AsyncEventSequencer> sequencer(
- new dbus_utils::AsyncEventSequencer());
+ scoped_refptr<AsyncEventSequencer> sequencer(
+ new AsyncEventSequencer());
exported_object_->ExportMethod(
dbus_constants::kManagerInterface,
dbus_constants::kManagerCheckDeviceRegistered,
@@ -112,7 +120,14 @@
properties_->state_.SetValue("{}");
properties_->Init(
sequencer->GetHandler("Manager properties export failed.", true));
- sequencer->OnAllTasksCompletedCall({cb});
+ auto claim_interface_task = sequencer->WrapCompletionTask(
+ base::Bind(&dbus_utils::ExportedObjectManager::ClaimInterface,
+ object_manager_->AsWeakPtr(),
+ dbus::ObjectPath(dbus_constants::kManagerServicePath),
+ dbus_constants::kManagerInterface,
+ properties_->GetPropertyWriter(
+ dbus_constants::kManagerInterface)));
+ sequencer->OnAllTasksCompletedCall({claim_interface_task, cb});
device_info_.Load();
}
diff --git a/buffet/manager.h b/buffet/manager.h
index a508d81..4498c50 100644
--- a/buffet/manager.h
+++ b/buffet/manager.h
@@ -10,6 +10,7 @@
#include <base/basictypes.h>
#include <base/memory/scoped_ptr.h>
+#include <base/memory/weak_ptr.h>
#include <base/values.h>
#include <dbus/message.h>
#include <dbus/object_path.h>
@@ -20,7 +21,9 @@
namespace buffet {
-class DBusManager;
+namespace dbus_utils {
+class ExportedObjectManager;
+} // namespace dbus_utils
// The Manager is responsible for global state of Buffet. It exposes
// interfaces which affect the entire device such as device registration and
@@ -29,7 +32,8 @@
public:
typedef base::Callback<void(bool success)> OnInitFinish;
- explicit Manager(dbus::Bus* bus);
+ Manager(scoped_refptr<dbus::Bus> bus,
+ base::WeakPtr<dbus_utils::ExportedObjectManager> object_manager);
~Manager();
void Init(const OnInitFinish& cb);
@@ -64,8 +68,9 @@
scoped_ptr<::dbus::Response> HandleTestMethod(
::dbus::MethodCall* method_call);
- dbus::Bus* bus_;
+ scoped_refptr<dbus::Bus> bus_;
dbus::ExportedObject* exported_object_; // weak; owned by the Bus object.
+ base::WeakPtr<dbus_utils::ExportedObjectManager> object_manager_;
scoped_ptr<Properties> properties_;
DeviceRegistrationInfo device_info_;