| // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "buffet/manager.h" |
| |
| #include <map> |
| #include <string> |
| |
| #include <base/bind.h> |
| #include <base/bind_helpers.h> |
| #include <base/json/json_writer.h> |
| #include <dbus/bus.h> |
| #include <dbus/object_path.h> |
| #include <dbus/values_util.h> |
| |
| #include "buffet/async_event_sequencer.h" |
| #include "buffet/commands/command_manager.h" |
| #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( |
| scoped_refptr<dbus::Bus> bus, |
| base::WeakPtr<dbus_utils::ExportedObjectManager> object_manager) |
| : bus_(bus), |
| exported_object_(bus->GetExportedObject( |
| 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 |
| // our callbacks in between the Manager's death and the bus unregistering |
| // our exported object on shutdown. Unretained makes no promises of memory |
| // management. |
| exported_object_->Unregister(); |
| exported_object_ = nullptr; |
| } |
| |
| void Manager::Init(const OnInitFinish& cb) { |
| scoped_refptr<AsyncEventSequencer> sequencer( |
| new AsyncEventSequencer()); |
| exported_object_->ExportMethod( |
| dbus_constants::kManagerInterface, |
| dbus_constants::kManagerCheckDeviceRegistered, |
| dbus_utils::GetExportableDBusMethod( |
| base::Bind(&Manager::HandleCheckDeviceRegistered, |
| base::Unretained(this))), |
| sequencer->GetExportHandler( |
| dbus_constants::kManagerInterface, |
| dbus_constants::kManagerCheckDeviceRegistered, |
| "Failed exporting CheckDeviceRegistered method", |
| true)); |
| exported_object_->ExportMethod( |
| dbus_constants::kManagerInterface, |
| dbus_constants::kManagerGetDeviceInfo, |
| dbus_utils::GetExportableDBusMethod( |
| base::Bind(&Manager::HandleGetDeviceInfo, |
| base::Unretained(this))), |
| sequencer->GetExportHandler( |
| dbus_constants::kManagerInterface, |
| dbus_constants::kManagerGetDeviceInfo, |
| "Failed exporting GetDeviceInfo method", |
| true)); |
| exported_object_->ExportMethod( |
| dbus_constants::kManagerInterface, |
| dbus_constants::kManagerStartRegisterDevice, |
| dbus_utils::GetExportableDBusMethod( |
| base::Bind(&Manager::HandleStartRegisterDevice, |
| base::Unretained(this))), |
| sequencer->GetExportHandler( |
| dbus_constants::kManagerInterface, |
| dbus_constants::kManagerStartRegisterDevice, |
| "Failed exporting StartRegisterDevice method", |
| true)); |
| exported_object_->ExportMethod( |
| dbus_constants::kManagerInterface, |
| dbus_constants::kManagerFinishRegisterDevice, |
| dbus_utils::GetExportableDBusMethod( |
| base::Bind(&Manager::HandleFinishRegisterDevice, |
| base::Unretained(this))), |
| sequencer->GetExportHandler( |
| dbus_constants::kManagerInterface, |
| dbus_constants::kManagerFinishRegisterDevice, |
| "Failed exporting FinishRegisterDevice method", |
| true)); |
| exported_object_->ExportMethod( |
| dbus_constants::kManagerInterface, |
| dbus_constants::kManagerUpdateStateMethod, |
| dbus_utils::GetExportableDBusMethod( |
| base::Bind(&Manager::HandleUpdateState, |
| base::Unretained(this))), |
| sequencer->GetExportHandler( |
| dbus_constants::kManagerInterface, |
| dbus_constants::kManagerUpdateStateMethod, |
| "Failed exporting UpdateState method", |
| true)); |
| exported_object_->ExportMethod( |
| dbus_constants::kManagerInterface, dbus_constants::kManagerTestMethod, |
| dbus_utils::GetExportableDBusMethod( |
| base::Bind(&Manager::HandleTestMethod, base::Unretained(this))), |
| sequencer->GetExportHandler( |
| dbus_constants::kManagerInterface, dbus_constants::kManagerTestMethod, |
| "Failed exporting TestMethod method", |
| true)); |
| properties_.reset(new Properties(bus_)); |
| // TODO(wiley): Initialize all properties appropriately before claiming |
| // the properties interface. |
| properties_->state_.SetValue("{}"); |
| properties_->Init( |
| sequencer->GetHandler("Manager properties export failed.", true)); |
| 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}); |
| command_manager_ = std::make_shared<CommandManager>(); |
| command_manager_->Startup(); |
| device_info_ = std::unique_ptr<DeviceRegistrationInfo>( |
| new DeviceRegistrationInfo(command_manager_)); |
| device_info_->Load(); |
| } |
| |
| scoped_ptr<dbus::Response> Manager::HandleCheckDeviceRegistered( |
| dbus::MethodCall* method_call) { |
| // Read the parameters to the method. |
| dbus::MessageReader reader(method_call); |
| if (reader.HasMoreData()) { |
| return GetBadArgsError(method_call, |
| "Too many parameters to CheckDeviceRegistered"); |
| } |
| |
| LOG(INFO) << "Received call to Manager.CheckDeviceRegistered()"; |
| |
| buffet::ErrorPtr error; |
| bool registered = device_info_->CheckRegistration(&error); |
| // If it fails due to any reason other than 'device not registered', |
| // treat it as a real error and report it to the caller. |
| if (!registered && |
| !error->HasError(kErrorDomainGCD, "device_not_registered")) { |
| return GetDBusError(method_call, error.get()); |
| } |
| |
| std::string device_id; |
| if (registered) { |
| device_id = device_info_->GetDeviceId(&error); |
| if (device_id.empty()) |
| return GetDBusError(method_call, error.get()); |
| } |
| // Send back our response. |
| scoped_ptr<dbus::Response> response( |
| dbus::Response::FromMethodCall(method_call)); |
| dbus::MessageWriter writer(response.get()); |
| writer.AppendString(device_id); |
| return response.Pass(); |
| } |
| |
| scoped_ptr<dbus::Response> Manager::HandleGetDeviceInfo( |
| dbus::MethodCall* method_call) { |
| // Read the parameters to the method. |
| dbus::MessageReader reader(method_call); |
| if (reader.HasMoreData()) { |
| return GetBadArgsError(method_call, |
| "Too many parameters to GetDeviceInfo"); |
| } |
| |
| LOG(INFO) << "Received call to Manager.GetDeviceInfo()"; |
| |
| std::string device_info_str; |
| buffet::ErrorPtr error; |
| auto device_info = device_info_->GetDeviceInfo(&error); |
| if (!device_info) |
| return GetDBusError(method_call, error.get()); |
| |
| base::JSONWriter::Write(device_info.get(), &device_info_str); |
| |
| // Send back our response. |
| scoped_ptr<dbus::Response> response( |
| dbus::Response::FromMethodCall(method_call)); |
| dbus::MessageWriter writer(response.get()); |
| writer.AppendString(device_info_str); |
| return response.Pass(); |
| } |
| |
| scoped_ptr<dbus::Response> Manager::HandleStartRegisterDevice( |
| dbus::MethodCall* method_call) { |
| // Read the parameters to the method. |
| dbus::MessageReader reader(method_call); |
| if (!reader.HasMoreData()) { |
| return GetBadArgsError(method_call, "No parameters to StartRegisterDevice"); |
| } |
| |
| dbus::MessageReader array_reader(nullptr); |
| if (!reader.PopArray(&array_reader)) |
| return GetBadArgsError(method_call, "Failed to read the parameter array"); |
| std::map<std::string, std::shared_ptr<base::Value>> params; |
| while (array_reader.HasMoreData()) { |
| dbus::MessageReader dict_entry_reader(nullptr); |
| if (!array_reader.PopDictEntry(&dict_entry_reader)) |
| return GetBadArgsError(method_call, "Failed to get a call parameter"); |
| std::string key; |
| if (!dict_entry_reader.PopString(&key)) |
| return GetBadArgsError(method_call, "Failed to read parameter key"); |
| base::Value* value = dbus::PopDataAsValue(&dict_entry_reader); |
| if (!value) |
| return GetBadArgsError(method_call, "Failed to read parameter value"); |
| params.insert(std::make_pair(key, std::shared_ptr<base::Value>(value))); |
| } |
| if (reader.HasMoreData()) |
| return GetBadArgsError(method_call, |
| "Too many parameters to StartRegisterDevice"); |
| |
| LOG(INFO) << "Received call to Manager.StartRegisterDevice()"; |
| |
| buffet::ErrorPtr error; |
| std::string id = device_info_->StartRegistration(params, &error); |
| if (id.empty()) |
| return GetDBusError(method_call, error.get()); |
| |
| // Send back our response. |
| scoped_ptr<dbus::Response> response( |
| dbus::Response::FromMethodCall(method_call)); |
| dbus::MessageWriter writer(response.get()); |
| writer.AppendString(id); |
| return response.Pass(); |
| } |
| |
| scoped_ptr<dbus::Response> Manager::HandleFinishRegisterDevice( |
| dbus::MethodCall* method_call) { |
| // Read the parameters to the method. |
| dbus::MessageReader reader(method_call); |
| if (!reader.HasMoreData()) { |
| return GetBadArgsError(method_call, |
| "No parameters to FinishRegisterDevice"); |
| } |
| std::string user_auth_code; |
| if (!reader.PopString(&user_auth_code)) { |
| return GetBadArgsError(method_call, "Failed to read UserAuthCode"); |
| } |
| if (reader.HasMoreData()) { |
| return GetBadArgsError(method_call, |
| "Too many parameters to FinishRegisterDevice"); |
| } |
| |
| LOG(INFO) << "Received call to Manager.FinishRegisterDevice()"; |
| buffet::ErrorPtr error; |
| if (!device_info_->FinishRegistration(user_auth_code, &error)) |
| return GetDBusError(method_call, error.get()); |
| |
| std::string device_id = device_info_->GetDeviceId(&error); |
| if (device_id.empty()) |
| return GetDBusError(method_call, error.get()); |
| |
| // Send back our response. |
| scoped_ptr<dbus::Response> response( |
| dbus::Response::FromMethodCall(method_call)); |
| dbus::MessageWriter writer(response.get()); |
| writer.AppendString(device_id); |
| return response.Pass(); |
| } |
| |
| scoped_ptr<dbus::Response> Manager::HandleUpdateState( |
| dbus::MethodCall *method_call) { |
| // Read the parameters to the method. |
| dbus::MessageReader reader(method_call); |
| if (!reader.HasMoreData()) { |
| return GetBadArgsError(method_call, "No parameters to UpdateState"); |
| } |
| std::string json_state_fragment; |
| if (!reader.PopString(&json_state_fragment)) { |
| return GetBadArgsError(method_call, "Failed to read json_state_fragment"); |
| } |
| if (reader.HasMoreData()) { |
| return GetBadArgsError(method_call, "Too many parameters to UpdateState"); |
| } |
| |
| LOG(INFO) << "Received call to Manager.UpdateState()"; |
| // TODO(wiley): Merge json state blobs intelligently. |
| properties_->state_.SetValue(json_state_fragment); |
| |
| // Send back our response. |
| return dbus::Response::FromMethodCall(method_call); |
| } |
| |
| scoped_ptr<dbus::Response> Manager::HandleTestMethod( |
| dbus::MethodCall* method_call) { |
| LOG(INFO) << "Received call to test method."; |
| return scoped_ptr<dbus::Response>(); |
| } |
| |
| } // namespace buffet |