blob: 6097b09112ba3204e6a4cfa3e8960f789ff1ab34 [file] [log] [blame]
Christopher Wileya4915c42014-03-27 14:45:37 -07001// Copyright 2014 The Chromium OS 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
5#include "buffet/manager.h"
6
Alex Vakulenkob3aac252014-05-07 17:35:24 -07007#include <map>
8#include <string>
9
Christopher Wileya4915c42014-03-27 14:45:37 -070010#include <base/bind.h>
11#include <base/bind_helpers.h>
Alex Vakulenko665c8852014-09-11 16:57:24 -070012#include <base/json/json_reader.h>
Christopher Wileyb76eb292014-05-05 16:09:16 -070013#include <base/json/json_writer.h>
Christopher Wileycd419662015-02-06 17:51:43 -080014#include <base/time/time.h>
Alex Vakulenkoa8b95bc2014-08-27 11:00:57 -070015#include <chromeos/dbus/async_event_sequencer.h>
16#include <chromeos/dbus/exported_object_manager.h>
17#include <chromeos/errors/error.h>
Anton Muhin332df192014-11-22 05:59:14 +040018#include <chromeos/key_value_store.h>
Christopher Wileyb76eb292014-05-05 16:09:16 -070019#include <dbus/bus.h>
Christopher Wiley90016242014-04-01 17:33:29 -070020#include <dbus/object_path.h>
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070021#include <dbus/values_util.h>
Christopher Wileya4915c42014-03-27 14:45:37 -070022
Alex Vakulenko665c8852014-09-11 16:57:24 -070023#include "buffet/commands/command_instance.h"
Alex Vakulenkoc2bc9a42014-07-23 10:57:58 -070024#include "buffet/commands/command_manager.h"
Alex Vakulenko57123b22014-10-28 13:50:16 -070025#include "buffet/states/state_change_queue.h"
Alex Vakulenko07216fe2014-09-19 15:31:09 -070026#include "buffet/states/state_manager.h"
Christopher Wileye0fdeee2015-02-07 18:29:32 -080027#include "buffet/storage_impls.h"
Christopher Wileya4915c42014-03-27 14:45:37 -070028
Christopher Wiley2d2d92b2014-07-29 14:07:10 -070029using chromeos::dbus_utils::AsyncEventSequencer;
Christopher Wileyb5dd5ea2014-08-11 10:51:20 -070030using chromeos::dbus_utils::ExportedObjectManager;
Christopher Wileya4915c42014-03-27 14:45:37 -070031
32namespace buffet {
33
Alex Vakulenko57123b22014-10-28 13:50:16 -070034namespace {
35// Max of 100 state update events should be enough in the queue.
36const size_t kMaxStateChangeQueueSize = 100;
37} // anonymous namespace
38
Alex Vakulenkof2784de2014-08-15 11:49:35 -070039Manager::Manager(const base::WeakPtr<ExportedObjectManager>& object_manager)
40 : dbus_object_(object_manager.get(),
41 object_manager->GetBus(),
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -070042 org::chromium::Buffet::ManagerAdaptor::GetObjectPath()) {
43}
Christopher Wileya4915c42014-03-27 14:45:37 -070044
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -070045Manager::~Manager() {
46}
Alex Vakulenko57123b22014-10-28 13:50:16 -070047
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -070048void Manager::RegisterAsync(const base::FilePath& config_path,
49 const base::FilePath& state_path,
50 const base::FilePath& test_definitions_path,
51 const AsyncEventSequencer::CompletionAction& cb) {
Alex Vakulenko95110752014-09-03 16:27:21 -070052 command_manager_ =
53 std::make_shared<CommandManager>(dbus_object_.GetObjectManager());
Vitaly Bukaaabadee2015-03-18 23:33:44 -070054 command_manager_->SetOnCommandDefChanged(
55 base::Bind(&Manager::OnCommandDefsChanged, base::Unretained(this)));
Christopher Wileybb5b8482015-02-12 13:42:16 -080056 command_manager_->Startup(base::FilePath{"/etc/buffet"},
57 test_definitions_path);
Alex Vakulenko57123b22014-10-28 13:50:16 -070058 state_change_queue_ = std::unique_ptr<StateChangeQueue>(
59 new StateChangeQueue(kMaxStateChangeQueueSize));
60 state_manager_ = std::make_shared<StateManager>(state_change_queue_.get());
Alex Vakulenko07216fe2014-09-19 15:31:09 -070061 state_manager_->Startup();
Christopher Wiley583d64b2015-03-24 14:30:17 -070062 std::unique_ptr<BuffetConfig> config{new BuffetConfig};
63 config->Load(config_path);
Christopher Wileye0fdeee2015-02-07 18:29:32 -080064 std::unique_ptr<FileStorage> state_store{new FileStorage{state_path}};
Christopher Wileye0fdeee2015-02-07 18:29:32 -080065 // TODO(avakulenko): Figure out security implications of storing
66 // device info state data unencrypted.
Alex Vakulenko1f30a622014-07-23 11:13:15 -070067 device_info_ = std::unique_ptr<DeviceRegistrationInfo>(
Christopher Wileyc900e482015-02-15 15:42:04 -080068 new DeviceRegistrationInfo(
69 command_manager_,
70 state_manager_,
Christopher Wiley583d64b2015-03-24 14:30:17 -070071 std::move(config),
Christopher Wileyc900e482015-02-15 15:42:04 -080072 chromeos::http::Transport::CreateDefault(),
73 std::move(state_store),
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -070074 base::Bind(&Manager::OnRegistrationStatusChanged,
Christopher Wileyc900e482015-02-15 15:42:04 -080075 base::Unretained(this))));
Vitaly Bukab055f152015-03-12 13:41:43 -070076 device_info_->Load();
Alex Vakulenko2348e422014-11-21 08:57:57 -080077 dbus_adaptor_.RegisterWithDBusObject(&dbus_object_);
78 dbus_object_.RegisterAsync(cb);
Christopher Wileya4915c42014-03-27 14:45:37 -070079}
80
Alex Vakulenko2348e422014-11-21 08:57:57 -080081void Manager::CheckDeviceRegistered(DBusMethodResponse<std::string> response) {
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070082 LOG(INFO) << "Received call to Manager.CheckDeviceRegistered()";
Alex Vakulenko5c7bf012014-10-30 16:28:38 -070083 chromeos::ErrorPtr error;
84 bool registered = device_info_->CheckRegistration(&error);
Alex Vakulenkob3aac252014-05-07 17:35:24 -070085 // If it fails due to any reason other than 'device not registered',
86 // treat it as a real error and report it to the caller.
87 if (!registered &&
Alex Vakulenko5c7bf012014-10-30 16:28:38 -070088 !error->HasError(kErrorDomainGCD, "device_not_registered")) {
89 response->ReplyWithError(error.get());
90 return;
Alex Vakulenkob3aac252014-05-07 17:35:24 -070091 }
Christopher Wileya4915c42014-03-27 14:45:37 -070092
Vitaly Buka620bd7e2015-03-16 01:07:01 -070093 response->Return(registered ? device_info_->GetDeviceId() : std::string());
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070094}
95
Alex Vakulenko2348e422014-11-21 08:57:57 -080096void Manager::GetDeviceInfo(DBusMethodResponse<std::string> response) {
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070097 LOG(INFO) << "Received call to Manager.GetDeviceInfo()";
98
Alex Vakulenko5c7bf012014-10-30 16:28:38 -070099 chromeos::ErrorPtr error;
100 auto device_info = device_info_->GetDeviceInfo(&error);
101 if (!device_info) {
102 response->ReplyWithError(error.get());
103 return;
104 }
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700105
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700106 std::string device_info_str;
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700107 base::JSONWriter::Write(device_info.get(), &device_info_str);
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700108 response->Return(device_info_str);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700109}
110
Alex Vakulenko2348e422014-11-21 08:57:57 -0800111void Manager::RegisterDevice(DBusMethodResponse<std::string> response,
112 const chromeos::VariantDictionary& params) {
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400113 LOG(INFO) << "Received call to Manager.RegisterDevice()";
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700114
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700115 chromeos::ErrorPtr error;
Alex Vakulenko2348e422014-11-21 08:57:57 -0800116 std::map<std::string, std::string> str_params;
117 for (const auto& pair : params) {
118 if (!pair.second.IsTypeCompatible<std::string>()) {
119 response->ReplyWithError(FROM_HERE, chromeos::errors::dbus::kDomain,
120 DBUS_ERROR_INVALID_ARGS,
121 "String value expected");
122 return;
123 }
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -0700124 str_params.emplace_hint(str_params.end(), pair.first,
125 pair.second.Get<std::string>());
Alex Vakulenko2348e422014-11-21 08:57:57 -0800126 }
127 std::string device_id = device_info_->RegisterDevice(str_params, &error);
David Zeuthen1dbad472015-02-12 15:24:21 -0500128 if (!device_id.empty()) {
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700129 response->Return(device_id);
David Zeuthen1dbad472015-02-12 15:24:21 -0500130 return;
131 }
132 if (!error) {
133 // TODO(zeuthen): This can be changed to CHECK(error) once
134 // RegisterDevice() has been fixed to set |error| when failing.
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -0700135 chromeos::Error::AddTo(&error, FROM_HERE, kErrorDomainGCD, "internal_error",
David Zeuthen1dbad472015-02-12 15:24:21 -0500136 "device_id empty but error not set");
137 }
138 response->ReplyWithError(error.get());
Christopher Wileya4915c42014-03-27 14:45:37 -0700139}
140
Alex Vakulenko2348e422014-11-21 08:57:57 -0800141void Manager::UpdateState(DBusMethodResponse<> response,
142 const chromeos::VariantDictionary& property_set) {
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700143 chromeos::ErrorPtr error;
Alex Vakulenkoff73cf22014-10-29 09:53:52 -0700144 base::Time timestamp = base::Time::Now();
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700145 bool all_success = true;
Alex Vakulenkoff73cf22014-10-29 09:53:52 -0700146 for (const auto& pair : property_set) {
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -0700147 if (!state_manager_->SetPropertyValue(pair.first, pair.second, timestamp,
148 &error)) {
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700149 // Remember that an error occurred but keep going and update the rest of
150 // the properties if possible.
151 all_success = false;
152 }
Alex Vakulenkoff73cf22014-10-29 09:53:52 -0700153 }
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700154 if (!all_success)
155 response->ReplyWithError(error.get());
156 else
157 response->Return();
Christopher Wileya4915c42014-03-27 14:45:37 -0700158}
159
Alex Vakulenko61ad4db2015-01-20 10:50:04 -0800160bool Manager::GetState(chromeos::ErrorPtr* error, std::string* state) {
161 auto json = state_manager_->GetStateValuesAsJson(error);
162 if (!json)
163 return false;
164 base::JSONWriter::Write(json.get(), state);
165 return true;
166}
167
Alex Vakulenko2348e422014-11-21 08:57:57 -0800168void Manager::AddCommand(DBusMethodResponse<> response,
169 const std::string& json_command) {
Anton Muhin5191e812014-10-30 17:49:48 +0400170 static int next_id = 0;
Alex Vakulenko665c8852014-09-11 16:57:24 -0700171 std::string error_message;
172 std::unique_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
173 json_command, base::JSON_PARSE_RFC, nullptr, &error_message));
174 if (!value) {
Alex Vakulenkoac8037d2014-11-11 11:42:05 -0800175 response->ReplyWithError(FROM_HERE, chromeos::errors::json::kDomain,
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700176 chromeos::errors::json::kParseError,
177 error_message);
Alex Vakulenko665c8852014-09-11 16:57:24 -0700178 return;
179 }
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700180 chromeos::ErrorPtr error;
Alex Vakulenko665c8852014-09-11 16:57:24 -0700181 auto command_instance = buffet::CommandInstance::FromJson(
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700182 value.get(), command_manager_->GetCommandDictionary(), &error);
183 if (!command_instance) {
184 response->ReplyWithError(error.get());
185 return;
186 }
Anton Muhin5191e812014-10-30 17:49:48 +0400187 command_instance->SetID(std::to_string(++next_id));
Alex Vakulenko5c7bf012014-10-30 16:28:38 -0700188 command_manager_->AddCommand(std::move(command_instance));
189 response->Return();
Alex Vakulenko665c8852014-09-11 16:57:24 -0700190}
191
Alex Vakulenko2348e422014-11-21 08:57:57 -0800192std::string Manager::TestMethod(const std::string& message) {
Alex Vakulenko7a1dc0b2014-08-15 11:45:46 -0700193 LOG(INFO) << "Received call to test method: " << message;
194 return message;
Christopher Wileyb76eb292014-05-05 16:09:16 -0700195}
196
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -0700197void Manager::OnRegistrationStatusChanged() {
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700198 dbus_adaptor_.SetStatus(
199 StatusToString(device_info_->GetRegistrationStatus()));
200 dbus_adaptor_.SetDeviceId(device_info_->GetDeviceId());
Christopher Wileyc900e482015-02-15 15:42:04 -0800201}
202
Vitaly Bukaaabadee2015-03-18 23:33:44 -0700203void Manager::OnCommandDefsChanged() {
204 chromeos::ErrorPtr error;
205 std::unique_ptr<base::DictionaryValue> commands =
206 command_manager_->GetCommandDictionary().GetCommandsAsJson(true, &error);
207 CHECK(commands);
208 std::string json;
209 base::JSONWriter::Write(commands.get(), &json);
210 dbus_adaptor_.SetCommandDefs(json);
211}
212
Christopher Wileya4915c42014-03-27 14:45:37 -0700213} // namespace buffet