blob: f471ded337b864f6b71bfdb3f893fc425a2b7be5 [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>
Alex Vakulenkof7754542015-06-26 12:59:50 -070015#include <base/message_loop/message_loop.h>
Christopher Wiley8994e012015-02-06 17:51:43 -080016#include <base/time/time.h>
Alex Vakulenko0022b752015-10-02 11:09:59 -070017#include <chromeos/bind_lambda.h>
Alex Vakulenko24e5f5d2014-08-27 11:00:57 -070018#include <chromeos/dbus/async_event_sequencer.h>
19#include <chromeos/dbus/exported_object_manager.h>
20#include <chromeos/errors/error.h>
Garret Kelly89ba0362015-05-29 15:56:52 -040021#include <chromeos/http/http_transport.h>
Alex Vakulenko0022b752015-10-02 11:09:59 -070022#include <chromeos/http/http_utils.h>
Anton Muhin53e882a2014-11-22 05:59:14 +040023#include <chromeos/key_value_store.h>
Vitaly Bukae74c8722015-08-13 00:33:00 -070024#include <chromeos/message_loops/message_loop.h>
Alex Vakulenko0022b752015-10-02 11:09:59 -070025#include <chromeos/mime_utils.h>
Christopher Wiley2ffa0042014-05-05 16:09:16 -070026#include <dbus/bus.h>
Christopher Wiley54028f92014-04-01 17:33:29 -070027#include <dbus/object_path.h>
Alex Vakulenkof3d77e52014-04-15 11:36:32 -070028#include <dbus/values_util.h>
Vitaly Bukae2713ac2015-08-03 13:50:01 -070029#include <weave/enum_to_string.h>
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070030
Robert Gindaf86123d2015-09-11 16:10:43 -070031#include "buffet/bluetooth_client.h"
Vitaly Buka1175a9b2015-08-15 10:42:17 -070032#include "buffet/buffet_config.h"
Vitaly Bukaa0305d32015-07-27 16:08:51 -070033#include "buffet/dbus_command_dispatcher.h"
34#include "buffet/dbus_conversion.h"
Vitaly Buka00882b72015-08-06 00:32:11 -070035#include "buffet/http_transport_client.h"
Alex Vakulenkof0f55342015-08-18 15:51:40 -070036#include "buffet/mdns_client.h"
Peter Qiu786a9062015-10-02 11:45:01 -070037#include "buffet/shill_client.h"
Vitaly Buka4f771532015-08-14 14:58:39 -070038#include "buffet/weave_error_conversion.h"
Alex Vakulenko1642bec2015-08-19 09:34:58 -070039#include "buffet/webserv_client.h"
Vitaly Buka03319c22015-07-17 14:48:30 -070040
Christopher Wiley68c07cc2014-07-29 14:07:10 -070041using chromeos::dbus_utils::AsyncEventSequencer;
Christopher Wiley1aa980e2014-08-11 10:51:20 -070042using chromeos::dbus_utils::ExportedObjectManager;
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070043
44namespace buffet {
45
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070046namespace {
Vitaly Buka7b3ba792015-06-09 17:01:54 -070047
Vitaly Buka7b3ba792015-06-09 17:01:54 -070048const char kPairingSessionIdKey[] = "sessionId";
49const char kPairingModeKey[] = "mode";
50const char kPairingCodeKey[] = "code";
51
Vitaly Buka0c6dcd22015-07-10 00:12:25 -070052const char kErrorDomain[] = "buffet";
Vitaly Buka0c6dcd22015-07-10 00:12:25 -070053
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070054} // anonymous namespace
55
Alex Vakulenkoe32375b2015-09-28 08:55:40 -070056class Manager::TaskRunner : public weave::provider::TaskRunner {
Vitaly Bukae74c8722015-08-13 00:33:00 -070057 public:
58 void PostDelayedTask(const tracked_objects::Location& from_here,
59 const base::Closure& task,
60 base::TimeDelta delay) override {
61 chromeos::MessageLoop::current()->PostDelayedTask(from_here, task, delay);
62 }
63};
64
Alex Vakulenkob6351532014-08-15 11:49:35 -070065Manager::Manager(const base::WeakPtr<ExportedObjectManager>& object_manager)
66 : dbus_object_(object_manager.get(),
67 object_manager->GetBus(),
Alex Vakulenko63bdf082015-08-21 09:27:12 -070068 com::android::Weave::ManagerAdaptor::GetObjectPath()) {
Vitaly Buka91cc7152015-03-20 09:46:57 -070069}
Christopher Wiley4b5f04c2014-03-27 14:45:37 -070070
Vitaly Buka91cc7152015-03-20 09:46:57 -070071Manager::~Manager() {
72}
Alex Vakulenkoecf961a2014-10-28 13:50:16 -070073
Alex Vakulenko0022b752015-10-02 11:09:59 -070074void Manager::Start(const Options& options,
75 const BuffetConfig::Options& paths,
Vitaly Buka58a288b2015-07-31 00:33:31 -070076 const std::set<std::string>& device_whitelist,
Vitaly Buka0c6dcd22015-07-10 00:12:25 -070077 AsyncEventSequencer* sequencer) {
Vitaly Bukae74c8722015-08-13 00:33:00 -070078 task_runner_.reset(new TaskRunner{});
Vitaly Buka00882b72015-08-06 00:32:11 -070079 http_client_.reset(new HttpTransportClient);
Alex Vakulenko0022b752015-10-02 11:09:59 -070080 shill_client_.reset(new ShillClient{dbus_object_.GetBus(), device_whitelist,
81 !options.xmpp_enabled});
82 weave::provider::HttpServer* http_server{nullptr};
Christopher Wileye925bb32015-08-03 20:09:18 -070083#ifdef BUFFET_USE_WIFI_BOOTSTRAPPING
Alex Vakulenkof0f55342015-08-18 15:51:40 -070084 if (!options.disable_privet) {
Robert Gindacf92c662015-08-20 09:30:11 -070085 mdns_client_ = MdnsClient::CreateInstance(dbus_object_.GetBus());
Alex Vakulenko1642bec2015-08-19 09:34:58 -070086 web_serv_client_.reset(new WebServClient{dbus_object_.GetBus(), sequencer});
Robert Gindaf86123d2015-09-11 16:10:43 -070087 bluetooth_client_ = BluetoothClient::CreateInstance();
Alex Vakulenko0022b752015-10-02 11:09:59 -070088 http_server = web_serv_client_.get();
89
90 if (options.enable_ping) {
91 http_server->AddRequestHandler(
92 "/privet/ping",
93 base::Bind(
94 [](const weave::provider::HttpServer::Request& request,
95 const weave::provider::HttpServer::OnReplyCallback& callback) {
96 callback.Run(chromeos::http::status_code::Ok, "Hello, world!",
97 chromeos::mime::text::kPlain);
98 }));
99 }
Alex Vakulenkof0f55342015-08-18 15:51:40 -0700100 }
Christopher Wileye925bb32015-08-03 20:09:18 -0700101#endif // BUFFET_USE_WIFI_BOOTSTRAPPING
Vitaly Buka7042c582015-07-30 17:02:14 -0700102
Vitaly Bukabecd4612015-08-16 23:31:55 -0700103 config_.reset(new BuffetConfig{paths});
Alex Vakulenko0022b752015-10-02 11:09:59 -0700104 device_ = weave::Device::Create(config_.get(), task_runner_.get(),
105 http_client_.get(), shill_client_.get(),
106 mdns_client_.get(), web_serv_client_.get(),
107 shill_client_.get(), bluetooth_client_.get());
Vitaly Buka1175a9b2015-08-15 10:42:17 -0700108
Alex Vakulenko0022b752015-10-02 11:09:59 -0700109 device_->AddSettingsChangedCallback(
110 base::Bind(&Manager::OnConfigChanged, weak_ptr_factory_.GetWeakPtr()));
Vitaly Buka0c6dcd22015-07-10 00:12:25 -0700111
Vitaly Bukaa0305d32015-07-27 16:08:51 -0700112 command_dispatcher_.reset(new DBusCommandDispacher{
Vitaly Bukae8c3bab2015-07-29 16:39:34 -0700113 dbus_object_.GetObjectManager(), device_->GetCommands()});
114
Alex Vakulenko0022b752015-10-02 11:09:59 -0700115 device_->AddStateChangedCallback(
Vitaly Buka2b30e7a2015-05-27 09:27:08 -0700116 base::Bind(&Manager::OnStateChanged, weak_ptr_factory_.GetWeakPtr()));
Vitaly Bukabf4ba652015-05-14 16:57:23 -0700117
Alex Vakulenko0022b752015-10-02 11:09:59 -0700118 device_->AddGcdStateChangedCallback(
119 base::Bind(&Manager::OnGcdStateChanged, weak_ptr_factory_.GetWeakPtr()));
Vitaly Bukae74fe3c2015-05-13 13:48:59 -0700120
Alex Vakulenko0022b752015-10-02 11:09:59 -0700121 if (!options.disable_privet) {
122 device_->AddPairingChangedCallbacks(
Vitaly Buka1d63c9c2015-07-17 14:34:35 -0700123 base::Bind(&Manager::OnPairingStart, weak_ptr_factory_.GetWeakPtr()),
124 base::Bind(&Manager::OnPairingEnd, weak_ptr_factory_.GetWeakPtr()));
Vitaly Buka1d63c9c2015-07-17 14:34:35 -0700125 }
Vitaly Buka84fd6dd2015-06-09 17:22:18 -0700126
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800127 dbus_adaptor_.RegisterWithDBusObject(&dbus_object_);
Vitaly Buka84fd6dd2015-06-09 17:22:18 -0700128 dbus_object_.RegisterAsync(
129 sequencer->GetHandler("Manager.RegisterAsync() failed.", true));
Vitaly Buka84fd6dd2015-06-09 17:22:18 -0700130}
131
132void Manager::Stop() {
Vitaly Buka0c6dcd22015-07-10 00:12:25 -0700133 device_.reset();
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700134}
135
Alex Vakulenko6c375262015-06-19 11:01:42 -0700136void Manager::RegisterDevice(DBusMethodResponsePtr<std::string> response,
Vitaly Bukacbadabe2015-05-14 23:33:32 -0700137 const std::string& ticket_id) {
Anton Muhin9cc03fd2014-10-16 18:59:57 +0400138 LOG(INFO) << "Received call to Manager.RegisterDevice()";
Alex Vakulenkof3d77e52014-04-15 11:36:32 -0700139
Vitaly Buka4f771532015-08-14 14:58:39 -0700140 weave::ErrorPtr error;
Alex Vakulenko0022b752015-10-02 11:09:59 -0700141 std::string device_id = device_->Register(ticket_id, &error);
David Zeuthen2101c082015-02-12 15:24:21 -0500142 if (!device_id.empty()) {
Alex Vakulenkob91dcfe2014-10-30 16:28:38 -0700143 response->Return(device_id);
David Zeuthen2101c082015-02-12 15:24:21 -0500144 return;
145 }
Vitaly Buka4f771532015-08-14 14:58:39 -0700146 chromeos::ErrorPtr chromeos_error;
147 ConvertError(*error, &chromeos_error);
148 response->ReplyWithError(chromeos_error.get());
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700149}
150
Alex Vakulenko6c375262015-06-19 11:01:42 -0700151void Manager::UpdateState(DBusMethodResponsePtr<> response,
Alex Vakulenko12e2c1a2014-11-21 08:57:57 -0800152 const chromeos::VariantDictionary& property_set) {
Vitaly Buka4f771532015-08-14 14:58:39 -0700153 chromeos::ErrorPtr chromeos_error;
154 auto properties =
155 DictionaryFromDBusVariantDictionary(property_set, &chromeos_error);
Vitaly Bukafb2584b2015-07-28 21:39:45 -0700156 if (!properties)
Alex Vakulenkoe32375b2015-09-28 08:55:40 -0700157 return response->ReplyWithError(chromeos_error.get());
Vitaly Bukafb2584b2015-07-28 21:39:45 -0700158
Vitaly Buka4f771532015-08-14 14:58:39 -0700159 weave::ErrorPtr error;
Alex Vakulenko0022b752015-10-02 11:09:59 -0700160 if (!device_->SetStateProperties(*properties, &error)) {
Vitaly Buka4f771532015-08-14 14:58:39 -0700161 ConvertError(*error, &chromeos_error);
Alex Vakulenkoe32375b2015-09-28 08:55:40 -0700162 return response->ReplyWithError(chromeos_error.get());
Vitaly Buka4f771532015-08-14 14:58:39 -0700163 }
164 response->Return();
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700165}
166
Alex Vakulenkoceab1772015-01-20 10:50:04 -0800167bool Manager::GetState(chromeos::ErrorPtr* error, std::string* state) {
Alex Vakulenko0022b752015-10-02 11:09:59 -0700168 auto json = device_->GetState();
Vitaly Bukacd5e5562015-07-28 15:33:55 -0700169 CHECK(json);
Nathan Bullockf5b91bf2015-04-01 15:32:58 -0400170 base::JSONWriter::WriteWithOptions(
Alex Vakulenkoab4e4ff2015-06-15 12:53:22 -0700171 *json, base::JSONWriter::OPTIONS_PRETTY_PRINT, state);
Alex Vakulenkoceab1772015-01-20 10:50:04 -0800172 return true;
173}
174
Alex Vakulenko6c375262015-06-19 11:01:42 -0700175void Manager::AddCommand(DBusMethodResponsePtr<std::string> response,
Alex Vakulenko0022b752015-10-02 11:09:59 -0700176 const std::string& json_command) {
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700177 std::string error_message;
Alex Vakulenkoab4e4ff2015-06-15 12:53:22 -0700178 std::unique_ptr<base::Value> value(
179 base::JSONReader::ReadAndReturnError(json_command, base::JSON_PARSE_RFC,
180 nullptr, &error_message)
181 .release());
Vitaly Bukaa4e8d7f2015-06-09 09:46:53 -0700182 const base::DictionaryValue* command{nullptr};
183 if (!value || !value->GetAsDictionary(&command)) {
184 return response->ReplyWithError(FROM_HERE, chromeos::errors::json::kDomain,
185 chromeos::errors::json::kParseError,
186 error_message);
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700187 }
Vitaly Bukaa4e8d7f2015-06-09 09:46:53 -0700188
Vitaly Bukaa4e8d7f2015-06-09 09:46:53 -0700189 std::string id;
Vitaly Buka4f771532015-08-14 14:58:39 -0700190 weave::ErrorPtr error;
Alex Vakulenko0022b752015-10-02 11:09:59 -0700191 if (!device_->GetCommands()->AddCommand(*command, &id, &error)) {
192 chromeos::ErrorPtr chromeos_error;
Vitaly Buka4f771532015-08-14 14:58:39 -0700193 ConvertError(*error, &chromeos_error);
194 return response->ReplyWithError(chromeos_error.get());
195 }
Vitaly Bukac03ec2b2015-05-31 23:32:46 -0700196
Vitaly Buka59af7ac2015-03-24 12:42:24 -0700197 response->Return(id);
Alex Vakulenko4f7778e2014-09-11 16:57:24 -0700198}
199
Alex Vakulenko6c375262015-06-19 11:01:42 -0700200void Manager::GetCommand(DBusMethodResponsePtr<std::string> response,
Vitaly Buka5515de02015-03-24 11:39:40 -0700201 const std::string& id) {
Vitaly Bukaba463732015-07-14 19:19:39 -0700202 const weave::Command* command = device_->GetCommands()->FindCommand(id);
Vitaly Buka5515de02015-03-24 11:39:40 -0700203 if (!command) {
Vitaly Buka0c6dcd22015-07-10 00:12:25 -0700204 response->ReplyWithError(FROM_HERE, kErrorDomain, "unknown_command",
Vitaly Buka5515de02015-03-24 11:39:40 -0700205 "Can't find command with id: " + id);
206 return;
207 }
208 std::string command_str;
Alex Vakulenkoab4e4ff2015-06-15 12:53:22 -0700209 base::JSONWriter::WriteWithOptions(
210 *command->ToJson(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &command_str);
Vitaly Buka5515de02015-03-24 11:39:40 -0700211 response->Return(command_str);
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 Buka2b30e7a2015-05-27 09:27:08 -0700219void Manager::OnStateChanged() {
Alex Vakulenko0022b752015-10-02 11:09:59 -0700220 auto state = device_->GetState();
Vitaly Buka2b30e7a2015-05-27 09:27:08 -0700221 CHECK(state);
222 std::string json;
223 base::JSONWriter::WriteWithOptions(
Alex Vakulenkoab4e4ff2015-06-15 12:53:22 -0700224 *state, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
Vitaly Buka2b30e7a2015-05-27 09:27:08 -0700225 dbus_adaptor_.SetState(json);
226}
227
Alex Vakulenko0022b752015-10-02 11:09:59 -0700228void Manager::OnGcdStateChanged(weave::GcdState state) {
229 dbus_adaptor_.SetStatus(weave::EnumToString(state));
Vitaly Bukabf4ba652015-05-14 16:57:23 -0700230}
231
Vitaly Buka00b83492015-07-20 00:37:48 -0700232void Manager::OnConfigChanged(const weave::Settings& settings) {
Alex Vakulenkoe4ef2612015-09-29 09:53:39 -0700233 dbus_adaptor_.SetDeviceId(settings.cloud_id);
Vitaly Buka00b83492015-07-20 00:37:48 -0700234 dbus_adaptor_.SetOemName(settings.oem_name);
235 dbus_adaptor_.SetModelName(settings.model_name);
236 dbus_adaptor_.SetModelId(settings.model_id);
237 dbus_adaptor_.SetName(settings.name);
238 dbus_adaptor_.SetDescription(settings.description);
239 dbus_adaptor_.SetLocation(settings.location);
Vitaly Buka7b3ba792015-06-09 17:01:54 -0700240}
241
242void Manager::OnPairingStart(const std::string& session_id,
Vitaly Buka0c6dcd22015-07-10 00:12:25 -0700243 weave::PairingType pairing_type,
Vitaly Buka7b3ba792015-06-09 17:01:54 -0700244 const std::vector<uint8_t>& code) {
245 // For now, just overwrite the exposed PairInfo with
246 // the most recent pairing attempt.
247 dbus_adaptor_.SetPairingInfo(chromeos::VariantDictionary{
248 {kPairingSessionIdKey, session_id},
Vitaly Buka03319c22015-07-17 14:48:30 -0700249 {kPairingModeKey, weave::EnumToString(pairing_type)},
Vitaly Buka7b3ba792015-06-09 17:01:54 -0700250 {kPairingCodeKey, code},
251 });
252}
253
254void Manager::OnPairingEnd(const std::string& session_id) {
255 auto exposed_pairing_attempt = dbus_adaptor_.GetPairingInfo();
256 auto it = exposed_pairing_attempt.find(kPairingSessionIdKey);
257 if (it == exposed_pairing_attempt.end()) {
258 return;
259 }
260 std::string exposed_session{it->second.TryGet<std::string>()};
261 if (exposed_session == session_id) {
262 dbus_adaptor_.SetPairingInfo(chromeos::VariantDictionary{});
263 }
264}
265
Christopher Wiley4b5f04c2014-03-27 14:45:37 -0700266} // namespace buffet