blob: c69dfdd71b011195d03a03bf95499f66a5a42948 [file] [log] [blame]
Christopher Wiley4b5f04c2014-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 Vakulenko7c3226e2014-05-07 17:35:24 -07007#include <map>
Alex Vakulenkoec41a0c2015-04-17 15:35:34 -07008#include <set>
Alex Vakulenko7c3226e2014-05-07 17:35:24 -07009#include <string>
10
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070011#include <base/bind.h>
12#include <base/bind_helpers.h>
Alex Vakulenko4f7778e2014-09-11 16:57:24 -070013#include <base/json/json_reader.h>
Christopher Wiley2ffa0042014-05-05 16:09:16 -070014#include <base/json/json_writer.h>
Christopher Wiley8994e012015-02-06 17:51:43 -080015#include <base/time/time.h>
Alex Vakulenko24e5f5d2014-08-27 11:00:57 -070016#include <chromeos/dbus/async_event_sequencer.h>
17#include <chromeos/dbus/exported_object_manager.h>
18#include <chromeos/errors/error.h>
Anton Muhin53e882a2014-11-22 05:59:14 +040019#include <chromeos/key_value_store.h>
Christopher Wiley2ffa0042014-05-05 16:09:16 -070020#include <dbus/bus.h>
Christopher Wiley54028f92014-04-01 17:33:29 -070021#include <dbus/object_path.h>
Alex Vakulenkof3d77e52014-04-15 11:36:32 -070022#include <dbus/values_util.h>
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070023
Vitaly Bukae74fe3c2015-05-13 13:48:59 -070024#include "buffet/base_api_handler.h"
Alex Vakulenko4f7778e2014-09-11 16:57:24 -070025#include "buffet/commands/command_instance.h"
Alex Vakulenkoacec6aa2015-04-20 11:00:54 -070026#include "buffet/commands/schema_constants.h"
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070027#include "buffet/states/state_change_queue.h"
Alex Vakulenko95877b52014-09-19 15:31:09 -070028#include "buffet/states/state_manager.h"
Christopher Wiley357deca2015-02-07 18:29:32 -080029#include "buffet/storage_impls.h"
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070030
Christopher Wiley68c07cc2014-07-29 14:07:10 -070031using chromeos::dbus_utils::AsyncEventSequencer;
Christopher Wiley1aa980e2014-08-11 10:51:20 -070032using chromeos::dbus_utils::ExportedObjectManager;
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070033
34namespace buffet {
35
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070036namespace {
37// Max of 100 state update events should be enough in the queue.
38const size_t kMaxStateChangeQueueSize = 100;
39} // anonymous namespace
40
Alex Vakulenkob6351532014-08-15 11:49:35 -070041Manager::Manager(const base::WeakPtr<ExportedObjectManager>& object_manager)
42 : dbus_object_(object_manager.get(),
43 object_manager->GetBus(),
Vitaly Buka91cc7152015-03-20 09:46:57 -070044 org::chromium::Buffet::ManagerAdaptor::GetObjectPath()) {
45}
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070046
Vitaly Buka91cc7152015-03-20 09:46:57 -070047Manager::~Manager() {
48}
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070049
Vitaly Bukae46525b2015-04-16 11:39:02 -070050void Manager::Start(const base::FilePath& config_path,
51 const base::FilePath& state_path,
52 const base::FilePath& test_definitions_path,
53 bool xmpp_enabled,
54 const AsyncEventSequencer::CompletionAction& cb) {
Alex Vakulenko05fa6812014-09-03 16:27:21 -070055 command_manager_ =
56 std::make_shared<CommandManager>(dbus_object_.GetObjectManager());
Vitaly Bukae43871f2015-05-11 15:41:33 -070057 command_manager_->AddOnCommandDefChanged(base::Bind(
58 &Manager::OnCommandDefsChanged, weak_ptr_factory_.GetWeakPtr()));
Christopher Wileyc39f4a32015-02-12 13:42:16 -080059 command_manager_->Startup(base::FilePath{"/etc/buffet"},
60 test_definitions_path);
Vitaly Bukae74fe3c2015-05-13 13:48:59 -070061 state_change_queue_.reset(new StateChangeQueue(kMaxStateChangeQueueSize));
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070062 state_manager_ = std::make_shared<StateManager>(state_change_queue_.get());
Vitaly Buka2b30e7a2015-05-27 09:27:08 -070063 state_manager_->AddOnChangedCallback(
64 base::Bind(&Manager::OnStateChanged, weak_ptr_factory_.GetWeakPtr()));
Alex Vakulenko95877b52014-09-19 15:31:09 -070065 state_manager_->Startup();
Vitaly Bukabf4ba652015-05-14 16:57:23 -070066
67 std::unique_ptr<BuffetConfig> config{new BuffetConfig{state_path}};
68 config->AddOnChangedCallback(
69 base::Bind(&Manager::OnConfigChanged, weak_ptr_factory_.GetWeakPtr()));
Christopher Wileyb024ca92015-03-24 14:30:17 -070070 config->Load(config_path);
Vitaly Bukabf4ba652015-05-14 16:57:23 -070071
Christopher Wiley357deca2015-02-07 18:29:32 -080072 // TODO(avakulenko): Figure out security implications of storing
73 // device info state data unencrypted.
Vitaly Bukae74fe3c2015-05-13 13:48:59 -070074 device_info_.reset(new DeviceRegistrationInfo(
75 command_manager_, state_manager_, std::move(config),
Vitaly Bukabf4ba652015-05-14 16:57:23 -070076 chromeos::http::Transport::CreateDefault(), xmpp_enabled));
77 device_info_->AddOnRegistrationChangedCallback(base::Bind(
78 &Manager::OnRegistrationChanged, weak_ptr_factory_.GetWeakPtr()));
Vitaly Bukae74fe3c2015-05-13 13:48:59 -070079
80 base_api_handler_.reset(
81 new BaseApiHandler{device_info_->AsWeakPtr(), command_manager_});
82
Vitaly Bukabf4ba652015-05-14 16:57:23 -070083 device_info_->Start();
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -080084 dbus_adaptor_.RegisterWithDBusObject(&dbus_object_);
85 dbus_object_.RegisterAsync(cb);
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070086}
87
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -080088void Manager::CheckDeviceRegistered(DBusMethodResponse<std::string> response) {
Alex Vakulenkof3d77e52014-04-15 11:36:32 -070089 LOG(INFO) << "Received call to Manager.CheckDeviceRegistered()";
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -070090 chromeos::ErrorPtr error;
Nathan Bullockeec58462015-04-08 15:13:07 -040091 bool registered = device_info_->HaveRegistrationCredentials(&error);
Alex Vakulenko7c3226e2014-05-07 17:35:24 -070092 // If it fails due to any reason other than 'device not registered',
93 // treat it as a real error and report it to the caller.
94 if (!registered &&
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -070095 !error->HasError(kErrorDomainGCD, "device_not_registered")) {
96 response->ReplyWithError(error.get());
97 return;
Alex Vakulenko7c3226e2014-05-07 17:35:24 -070098 }
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070099
Vitaly Bukabf4ba652015-05-14 16:57:23 -0700100 response->Return(registered ? device_info_->GetConfig().device_id()
101 : std::string());
Alex Vakulenkof3d77e52014-04-15 11:36:32 -0700102}
103
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800104void Manager::GetDeviceInfo(DBusMethodResponse<std::string> response) {
Alex Vakulenkof3d77e52014-04-15 11:36:32 -0700105 LOG(INFO) << "Received call to Manager.GetDeviceInfo()";
106
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700107 chromeos::ErrorPtr error;
108 auto device_info = device_info_->GetDeviceInfo(&error);
109 if (!device_info) {
110 response->ReplyWithError(error.get());
111 return;
112 }
Alex Vakulenko7c3226e2014-05-07 17:35:24 -0700113
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700114 std::string device_info_str;
Nathan Bullockf5b91bf2015-04-01 15:32:58 -0400115 base::JSONWriter::WriteWithOptions(device_info.get(),
116 base::JSONWriter::OPTIONS_PRETTY_PRINT, &device_info_str);
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700117 response->Return(device_info_str);
Alex Vakulenkof3d77e52014-04-15 11:36:32 -0700118}
119
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800120void Manager::RegisterDevice(DBusMethodResponse<std::string> response,
Vitaly Bukacbadabe2015-05-14 23:33:32 -0700121 const std::string& ticket_id) {
Anton Muhin9cc03fd2014-10-16 18:59:57 +0400122 LOG(INFO) << "Received call to Manager.RegisterDevice()";
Alex Vakulenkof3d77e52014-04-15 11:36:32 -0700123
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700124 chromeos::ErrorPtr error;
Vitaly Bukacbadabe2015-05-14 23:33:32 -0700125 std::string device_id = device_info_->RegisterDevice(ticket_id, &error);
David Zeuthen2101c082015-02-12 15:24:21 -0500126 if (!device_id.empty()) {
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700127 response->Return(device_id);
David Zeuthen2101c082015-02-12 15:24:21 -0500128 return;
129 }
130 if (!error) {
131 // TODO(zeuthen): This can be changed to CHECK(error) once
132 // RegisterDevice() has been fixed to set |error| when failing.
Vitaly Buka91cc7152015-03-20 09:46:57 -0700133 chromeos::Error::AddTo(&error, FROM_HERE, kErrorDomainGCD, "internal_error",
David Zeuthen2101c082015-02-12 15:24:21 -0500134 "device_id empty but error not set");
135 }
136 response->ReplyWithError(error.get());
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700137}
138
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800139void Manager::UpdateState(DBusMethodResponse<> response,
140 const chromeos::VariantDictionary& property_set) {
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700141 chromeos::ErrorPtr error;
Vitaly Buka14eb0ba2015-05-26 15:42:20 -0700142 if (!state_manager_->SetProperties(property_set, &error))
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700143 response->ReplyWithError(error.get());
144 else
145 response->Return();
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700146}
147
Alex Vakulenkoceab1772015-01-20 10:50:04 -0800148bool Manager::GetState(chromeos::ErrorPtr* error, std::string* state) {
149 auto json = state_manager_->GetStateValuesAsJson(error);
150 if (!json)
151 return false;
Nathan Bullockf5b91bf2015-04-01 15:32:58 -0400152 base::JSONWriter::WriteWithOptions(
153 json.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, state);
Alex Vakulenkoceab1772015-01-20 10:50:04 -0800154 return true;
155}
156
Vitaly Buka59af7ac2015-03-24 12:42:24 -0700157void Manager::AddCommand(DBusMethodResponse<std::string> response,
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800158 const std::string& json_command) {
Anton Muhind014d8b2014-10-30 17:49:48 +0400159 static int next_id = 0;
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700160 std::string error_message;
161 std::unique_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
162 json_command, base::JSON_PARSE_RFC, nullptr, &error_message));
163 if (!value) {
Alex Vakulenko90b3da92014-11-11 11:42:05 -0800164 response->ReplyWithError(FROM_HERE, chromeos::errors::json::kDomain,
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700165 chromeos::errors::json::kParseError,
166 error_message);
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700167 return;
168 }
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700169 chromeos::ErrorPtr error;
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700170 auto command_instance = buffet::CommandInstance::FromJson(
Alex Vakulenkod4190442015-04-20 12:33:52 -0700171 value.get(), commands::attributes::kCommand_Visibility_Local,
Alex Vakulenkoa031e1b2015-04-29 17:33:26 -0700172 command_manager_->GetCommandDictionary(), nullptr, &error);
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700173 if (!command_instance) {
174 response->ReplyWithError(error.get());
175 return;
176 }
Vitaly Buka59af7ac2015-03-24 12:42:24 -0700177 std::string id = std::to_string(++next_id);
178 command_instance->SetID(id);
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700179 command_manager_->AddCommand(std::move(command_instance));
Vitaly Buka59af7ac2015-03-24 12:42:24 -0700180 response->Return(id);
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700181}
182
Vitaly Buka5515de02015-03-24 11:39:40 -0700183void Manager::GetCommand(DBusMethodResponse<std::string> response,
184 const std::string& id) {
185 const CommandInstance* command = command_manager_->FindCommand(id);
186 if (!command) {
187 response->ReplyWithError(FROM_HERE, kErrorDomainGCD, "unknown_command",
188 "Can't find command with id: " + id);
189 return;
190 }
191 std::string command_str;
Nathan Bullockf5b91bf2015-04-01 15:32:58 -0400192 base::JSONWriter::WriteWithOptions(command->ToJson().get(),
193 base::JSONWriter::OPTIONS_PRETTY_PRINT, &command_str);
Vitaly Buka5515de02015-03-24 11:39:40 -0700194 response->Return(command_str);
195}
196
Alex Vakulenkoacec6aa2015-04-20 11:00:54 -0700197void Manager::SetCommandVisibility(
Alex Vakulenko8d78ebf2015-04-24 18:09:32 -0700198 std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<>> response,
Alex Vakulenkoacec6aa2015-04-20 11:00:54 -0700199 const std::vector<std::string>& in_names,
200 const std::string& in_visibility) {
201 CommandDefinition::Visibility visibility;
202 chromeos::ErrorPtr error;
203 if (!visibility.FromString(in_visibility, &error)) {
204 response->ReplyWithError(error.get());
205 return;
206 }
207 if (!command_manager_->SetCommandVisibility(in_names, visibility, &error)) {
208 response->ReplyWithError(error.get());
209 return;
210 }
211 response->Return();
212}
213
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800214std::string Manager::TestMethod(const std::string& message) {
Alex Vakulenko35e3bab2014-08-15 11:45:46 -0700215 LOG(INFO) << "Received call to test method: " << message;
216 return message;
Christopher Wiley2ffa0042014-05-05 16:09:16 -0700217}
218
Vitaly Buka760d6322015-04-17 00:41:31 -0700219bool Manager::UpdateDeviceInfo(chromeos::ErrorPtr* error,
220 const std::string& in_name,
221 const std::string& in_description,
222 const std::string& in_location) {
223 return device_info_->UpdateDeviceInfo(in_name, in_description, in_location,
224 error);
Christopher Wiley2f772932015-02-15 15:42:04 -0800225}
226
Vitaly Buka7cd01972015-05-14 21:25:45 -0700227bool Manager::UpdateServiceConfig(chromeos::ErrorPtr* error,
228 const std::string& client_id,
229 const std::string& client_secret,
230 const std::string& api_key,
231 const std::string& oauth_url,
232 const std::string& service_url) {
233 return device_info_->UpdateServiceConfig(client_id, client_secret, api_key,
234 oauth_url, service_url, error);
235}
236
Vitaly Buka1fa69012015-03-18 23:33:44 -0700237void Manager::OnCommandDefsChanged() {
Alex Vakulenkoec41a0c2015-04-17 15:35:34 -0700238 // Limit only to commands that are visible to the local clients.
239 auto commands = command_manager_->GetCommandDictionary().GetCommandsAsJson(
240 [](const buffet::CommandDefinition* def) {
241 return def->GetVisibility().local;
Vitaly Buka2b30e7a2015-05-27 09:27:08 -0700242 }, true, nullptr);
Vitaly Buka1fa69012015-03-18 23:33:44 -0700243 CHECK(commands);
244 std::string json;
Nathan Bullockf5b91bf2015-04-01 15:32:58 -0400245 base::JSONWriter::WriteWithOptions(commands.get(),
246 base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
Vitaly Buka1fa69012015-03-18 23:33:44 -0700247 dbus_adaptor_.SetCommandDefs(json);
248}
249
Vitaly Buka2b30e7a2015-05-27 09:27:08 -0700250void Manager::OnStateChanged() {
251 auto state = state_manager_->GetStateValuesAsJson(nullptr);
252 CHECK(state);
253 std::string json;
254 base::JSONWriter::WriteWithOptions(
255 state.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
256 dbus_adaptor_.SetState(json);
257}
258
Vitaly Bukabf4ba652015-05-14 16:57:23 -0700259void Manager::OnRegistrationChanged(RegistrationStatus status) {
260 dbus_adaptor_.SetStatus(StatusToString(status));
261}
262
263void Manager::OnConfigChanged(const BuffetConfig& config) {
264 dbus_adaptor_.SetDeviceId(config.device_id());
265 dbus_adaptor_.SetOemName(config.oem_name());
266 dbus_adaptor_.SetModelName(config.model_name());
267 dbus_adaptor_.SetModelId(config.model_id());
268 dbus_adaptor_.SetName(config.name());
269 dbus_adaptor_.SetDescription(config.description());
270 dbus_adaptor_.SetLocation(config.location());
271 dbus_adaptor_.SetAnonymousAccessRole(config.local_anonymous_access_role());
272}
273
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700274} // namespace buffet