1 // Copyright 2015 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "buffet/manager.h"
16
17 #include <map>
18 #include <set>
19 #include <string>
20
21 #include <base/bind.h>
22 #include <base/bind_helpers.h>
23 #include <base/files/file_enumerator.h>
24 #include <base/files/file_util.h>
25 #include <base/json/json_reader.h>
26 #include <base/json/json_writer.h>
27 #include <base/message_loop/message_loop.h>
28 #include <base/time/time.h>
29 #include <binderwrapper/binder_wrapper.h>
30 #include <cutils/properties.h>
31 #include <brillo/bind_lambda.h>
32 #include <brillo/errors/error.h>
33 #include <brillo/http/http_transport.h>
34 #include <brillo/http/http_utils.h>
35 #include <brillo/key_value_store.h>
36 #include <brillo/message_loops/message_loop.h>
37 #include <brillo/mime_utils.h>
38 #include <dbus/bus.h>
39 #include <dbus/object_path.h>
40 #include <dbus/values_util.h>
41 #include <weave/enum_to_string.h>
42
43 #include "brillo/weaved_system_properties.h"
44 #include "buffet/bluetooth_client.h"
45 #include "buffet/buffet_config.h"
46 #include "buffet/http_transport_client.h"
47 #include "buffet/mdns_client.h"
48 #include "buffet/shill_client.h"
49 #include "buffet/weave_error_conversion.h"
50 #include "buffet/webserv_client.h"
51 #include "common/binder_utils.h"
52
53 using brillo::dbus_utils::AsyncEventSequencer;
54 using NotificationListener =
55 android::weave::IWeaveServiceManagerNotificationListener;
56
57 namespace buffet {
58
59 namespace {
60
61 const char kErrorDomain[] = "buffet";
62 const char kFileReadError[] = "file_read_error";
63 const char kBaseComponent[] = "base";
64 const char kRebootCommand[] = "base.reboot";
65
LoadFile(const base::FilePath & file_path,std::string * data,brillo::ErrorPtr * error)66 bool LoadFile(const base::FilePath& file_path,
67 std::string* data,
68 brillo::ErrorPtr* error) {
69 if (!base::ReadFileToString(file_path, data)) {
70 brillo::errors::system::AddSystemError(error, FROM_HERE, errno);
71 brillo::Error::AddToPrintf(error, FROM_HERE, kErrorDomain, kFileReadError,
72 "Failed to read file '%s'",
73 file_path.value().c_str());
74 return false;
75 }
76 return true;
77 }
78
LoadTraitDefinitions(const BuffetConfig::Options & options,weave::Device * device)79 void LoadTraitDefinitions(const BuffetConfig::Options& options,
80 weave::Device* device) {
81 // Load component-specific device trait definitions.
82 base::FilePath dir{options.definitions.Append("traits")};
83 LOG(INFO) << "Looking for trait definitions in " << dir.value();
84 base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES,
85 FILE_PATH_LITERAL("*.json"));
86 std::vector<std::string> result;
87 for (base::FilePath path = enumerator.Next(); !path.empty();
88 path = enumerator.Next()) {
89 LOG(INFO) << "Loading trait definition from " << path.value();
90 std::string json;
91 CHECK(LoadFile(path, &json, nullptr));
92 device->AddTraitDefinitionsFromJson(json);
93 }
94 }
95
LoadCommandDefinitions(const BuffetConfig::Options & options,weave::Device * device)96 void LoadCommandDefinitions(const BuffetConfig::Options& options,
97 weave::Device* device) {
98 auto load_packages = [device](const base::FilePath& root,
99 const base::FilePath::StringType& pattern) {
100 base::FilePath dir{root.Append("commands")};
101 LOG(INFO) << "Looking for command schemas in " << dir.value();
102 base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES,
103 pattern);
104 for (base::FilePath path = enumerator.Next(); !path.empty();
105 path = enumerator.Next()) {
106 LOG(INFO) << "Loading command schema from " << path.value();
107 std::string json;
108 CHECK(LoadFile(path, &json, nullptr));
109 device->AddCommandDefinitionsFromJson(json);
110 }
111 };
112 load_packages(options.definitions, FILE_PATH_LITERAL("*.json"));
113 if (!options.test_definitions.empty())
114 load_packages(options.test_definitions, FILE_PATH_LITERAL("*test.json"));
115 }
116
LoadStateDefinitions(const BuffetConfig::Options & options,weave::Device * device)117 void LoadStateDefinitions(const BuffetConfig::Options& options,
118 weave::Device* device) {
119 // Load component-specific device state definitions.
120 base::FilePath dir{options.definitions.Append("states")};
121 LOG(INFO) << "Looking for state definitions in " << dir.value();
122 base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES,
123 FILE_PATH_LITERAL("*.schema.json"));
124 std::vector<std::string> result;
125 for (base::FilePath path = enumerator.Next(); !path.empty();
126 path = enumerator.Next()) {
127 LOG(INFO) << "Loading state definition from " << path.value();
128 std::string json;
129 CHECK(LoadFile(path, &json, nullptr));
130 device->AddStateDefinitionsFromJson(json);
131 }
132 }
133
LoadStateDefaults(const BuffetConfig::Options & options,weave::Device * device)134 void LoadStateDefaults(const BuffetConfig::Options& options,
135 weave::Device* device) {
136 // Load component-specific device state defaults.
137 base::FilePath dir{options.definitions.Append("states")};
138 LOG(INFO) << "Looking for state defaults in " << dir.value();
139 base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES,
140 FILE_PATH_LITERAL("*.defaults.json"));
141 std::vector<std::string> result;
142 for (base::FilePath path = enumerator.Next(); !path.empty();
143 path = enumerator.Next()) {
144 LOG(INFO) << "Loading state defaults from " << path.value();
145 std::string json;
146 CHECK(LoadFile(path, &json, nullptr));
147 CHECK(device->SetStatePropertiesFromJson(json, nullptr));
148 }
149 }
150
151 // Updates the manager's state property if the new value is different from
152 // the current value. In this case also adds the appropriate notification ID
153 // to the array to record the state change for clients.
UpdateValue(Manager * manager,std::string Manager::* prop,const std::string & new_value,int notification,std::vector<int> * notification_ids)154 void UpdateValue(Manager* manager,
155 std::string Manager::* prop,
156 const std::string& new_value,
157 int notification,
158 std::vector<int>* notification_ids) {
159 if (manager->*prop != new_value) {
160 manager->*prop = new_value;
161 notification_ids->push_back(notification);
162 }
163 }
164
165 } // anonymous namespace
166
167 class Manager::TaskRunner : public weave::provider::TaskRunner {
168 public:
PostDelayedTask(const tracked_objects::Location & from_here,const base::Closure & task,base::TimeDelta delay)169 void PostDelayedTask(const tracked_objects::Location& from_here,
170 const base::Closure& task,
171 base::TimeDelta delay) override {
172 brillo::MessageLoop::current()->PostDelayedTask(from_here, task, delay);
173 }
174 };
175
Manager(const Options & options,const scoped_refptr<dbus::Bus> & bus)176 Manager::Manager(const Options& options,
177 const scoped_refptr<dbus::Bus>& bus)
178 : options_{options}, bus_{bus} {}
179
~Manager()180 Manager::~Manager() {
181 android::BinderWrapper* binder_wrapper = android::BinderWrapper::Get();
182 for (const auto& listener : notification_listeners_) {
183 binder_wrapper->UnregisterForDeathNotifications(
184 android::IInterface::asBinder(listener));
185 }
186 for (const auto& pair : services_) {
187 binder_wrapper->UnregisterForDeathNotifications(
188 android::IInterface::asBinder(pair.first));
189 }
190 }
191
Start(AsyncEventSequencer * sequencer)192 void Manager::Start(AsyncEventSequencer* sequencer) {
193 power_manager_client_.Init();
194 RestartWeave(sequencer);
195 }
196
RestartWeave(AsyncEventSequencer * sequencer)197 void Manager::RestartWeave(AsyncEventSequencer* sequencer) {
198 Stop();
199
200 task_runner_.reset(new TaskRunner{});
201 config_.reset(new BuffetConfig{options_.config_options});
202 http_client_.reset(new HttpTransportClient);
203 shill_client_.reset(new ShillClient{bus_,
204 options_.device_whitelist,
205 !options_.xmpp_enabled});
206 weave::provider::HttpServer* http_server{nullptr};
207 #ifdef BUFFET_USE_WIFI_BOOTSTRAPPING
208 if (!options_.disable_privet) {
209 mdns_client_ = MdnsClient::CreateInstance();
210 web_serv_client_.reset(new WebServClient{
211 bus_, sequencer,
212 base::Bind(&Manager::CreateDevice, weak_ptr_factory_.GetWeakPtr())});
213 bluetooth_client_ = BluetoothClient::CreateInstance();
214 http_server = web_serv_client_.get();
215
216 if (options_.enable_ping) {
217 auto ping_handler = base::Bind(
218 [](std::unique_ptr<weave::provider::HttpServer::Request> request) {
219 request->SendReply(brillo::http::status_code::Ok, "Hello, world!",
220 brillo::mime::text::kPlain);
221 });
222 http_server->AddHttpRequestHandler("/privet/ping", ping_handler);
223 http_server->AddHttpsRequestHandler("/privet/ping", ping_handler);
224 }
225 }
226 #endif // BUFFET_USE_WIFI_BOOTSTRAPPING
227
228 if (!http_server)
229 CreateDevice();
230 }
231
CreateDevice()232 void Manager::CreateDevice() {
233 if (device_)
234 return;
235
236 device_ = weave::Device::Create(config_.get(), task_runner_.get(),
237 http_client_.get(), shill_client_.get(),
238 mdns_client_.get(), web_serv_client_.get(),
239 shill_client_.get(), bluetooth_client_.get());
240
241 LoadTraitDefinitions(options_.config_options, device_.get());
242 LoadCommandDefinitions(options_.config_options, device_.get());
243 LoadStateDefinitions(options_.config_options, device_.get());
244 LoadStateDefaults(options_.config_options, device_.get());
245
246 device_->AddSettingsChangedCallback(
247 base::Bind(&Manager::OnConfigChanged, weak_ptr_factory_.GetWeakPtr()));
248
249 device_->AddTraitDefsChangedCallback(
250 base::Bind(&Manager::OnTraitDefsChanged,
251 weak_ptr_factory_.GetWeakPtr()));
252 device_->AddStateChangedCallback(
253 base::Bind(&Manager::OnComponentTreeChanged,
254 weak_ptr_factory_.GetWeakPtr()));
255 device_->AddComponentTreeChangedCallback(
256 base::Bind(&Manager::OnComponentTreeChanged,
257 weak_ptr_factory_.GetWeakPtr()));
258
259 device_->AddGcdStateChangedCallback(
260 base::Bind(&Manager::OnGcdStateChanged, weak_ptr_factory_.GetWeakPtr()));
261
262 device_->AddPairingChangedCallbacks(
263 base::Bind(&Manager::OnPairingStart, weak_ptr_factory_.GetWeakPtr()),
264 base::Bind(&Manager::OnPairingEnd, weak_ptr_factory_.GetWeakPtr()));
265
266 device_->AddCommandHandler(kBaseComponent, kRebootCommand,
267 base::Bind(&Manager::OnRebootDevice,
268 weak_ptr_factory_.GetWeakPtr()));
269
270 CreateServicesForClients();
271 }
272
Stop()273 void Manager::Stop() {
274 device_.reset();
275 #ifdef BUFFET_USE_WIFI_BOOTSTRAPPING
276 web_serv_client_.reset();
277 mdns_client_.reset();
278 #endif // BUFFET_USE_WIFI_BOOTSTRAPPING
279 shill_client_.reset();
280 http_client_.reset();
281 config_.reset();
282 task_runner_.reset();
283 }
284
OnTraitDefsChanged()285 void Manager::OnTraitDefsChanged() {
286 NotifyServiceManagerChange({NotificationListener::TRAITS});
287 }
288
OnComponentTreeChanged()289 void Manager::OnComponentTreeChanged() {
290 NotifyServiceManagerChange({NotificationListener::COMPONENTS});
291 }
292
OnGcdStateChanged(weave::GcdState state)293 void Manager::OnGcdStateChanged(weave::GcdState state) {
294 state_ = weave::EnumToString(state);
295 NotifyServiceManagerChange({NotificationListener::STATE});
296 property_set(weaved::system_properties::kState, state_.c_str());
297 }
298
OnConfigChanged(const weave::Settings & settings)299 void Manager::OnConfigChanged(const weave::Settings& settings) {
300 std::vector<int> ids;
301 UpdateValue(this, &Manager::cloud_id_, settings.cloud_id,
302 NotificationListener::CLOUD_ID, &ids);
303 UpdateValue(this, &Manager::device_id_, settings.device_id,
304 NotificationListener::DEVICE_ID, &ids);
305 UpdateValue(this, &Manager::device_name_, settings.name,
306 NotificationListener::DEVICE_NAME, &ids);
307 UpdateValue(this, &Manager::device_description_, settings.description,
308 NotificationListener::DEVICE_DESCRIPTION, &ids);
309 UpdateValue(this, &Manager::device_location_, settings.location,
310 NotificationListener::DEVICE_LOCATION, &ids);
311 UpdateValue(this, &Manager::oem_name_, settings.oem_name,
312 NotificationListener::OEM_NAME, &ids);
313 UpdateValue(this, &Manager::model_id_, settings.model_id,
314 NotificationListener::MODEL_ID, &ids);
315 UpdateValue(this, &Manager::model_name_, settings.model_name,
316 NotificationListener::MODEL_NAME, &ids);
317 NotifyServiceManagerChange(ids);
318 }
319
OnPairingStart(const std::string & session_id,weave::PairingType pairing_type,const std::vector<uint8_t> & code)320 void Manager::OnPairingStart(const std::string& session_id,
321 weave::PairingType pairing_type,
322 const std::vector<uint8_t>& code) {
323 // For now, just overwrite the exposed PairInfo with the most recent pairing
324 // attempt.
325 std::vector<int> ids;
326 UpdateValue(this, &Manager::pairing_session_id_, session_id,
327 NotificationListener::PAIRING_SESSION_ID, &ids);
328 UpdateValue(this, &Manager::pairing_mode_, EnumToString(pairing_type),
329 NotificationListener::PAIRING_MODE, &ids);
330 std::string pairing_code{code.begin(), code.end()};
331 UpdateValue(this, &Manager::pairing_code_, pairing_code,
332 NotificationListener::PAIRING_CODE, &ids);
333 NotifyServiceManagerChange(ids);
334 }
335
OnPairingEnd(const std::string & session_id)336 void Manager::OnPairingEnd(const std::string& session_id) {
337 if (pairing_session_id_ != session_id)
338 return;
339 std::vector<int> ids;
340 UpdateValue(this, &Manager::pairing_session_id_, "",
341 NotificationListener::PAIRING_SESSION_ID, &ids);
342 UpdateValue(this, &Manager::pairing_mode_, "",
343 NotificationListener::PAIRING_MODE, &ids);
344 UpdateValue(this, &Manager::pairing_code_, "",
345 NotificationListener::PAIRING_CODE, &ids);
346 NotifyServiceManagerChange(ids);
347 }
348
OnRebootDevice(const std::weak_ptr<weave::Command> & cmd)349 void Manager::OnRebootDevice(const std::weak_ptr<weave::Command>& cmd) {
350 auto command = cmd.lock();
351 if (!command || !command->Complete({}, nullptr))
352 return;
353
354 task_runner_->PostDelayedTask(
355 FROM_HERE,
356 base::Bind(&Manager::RebootDeviceNow, weak_ptr_factory_.GetWeakPtr()),
357 base::TimeDelta::FromSeconds(2));
358 }
359
RebootDeviceNow()360 void Manager::RebootDeviceNow() {
361 power_manager_client_.Reboot(android::RebootReason::DEFAULT);
362 }
363
connect(const android::sp<android::weave::IWeaveClient> & client)364 android::binder::Status Manager::connect(
365 const android::sp<android::weave::IWeaveClient>& client) {
366 pending_clients_.push_back(client);
367 if (device_)
368 CreateServicesForClients();
369 return android::binder::Status::ok();
370 }
371
registerNotificationListener(const WeaveServiceManagerNotificationListener & listener)372 android::binder::Status Manager::registerNotificationListener(
373 const WeaveServiceManagerNotificationListener& listener) {
374 notification_listeners_.insert(listener);
375 android::BinderWrapper::Get()->RegisterForDeathNotifications(
376 android::IInterface::asBinder(listener),
377 base::Bind(&Manager::OnNotificationListenerDestroyed,
378 weak_ptr_factory_.GetWeakPtr(), listener));
379 return android::binder::Status::ok();
380 }
381
getCloudId(android::String16 * id)382 android::binder::Status Manager::getCloudId(android::String16* id) {
383 *id = weaved::binder_utils::ToString16(cloud_id_);
384 return android::binder::Status::ok();
385 }
386
getDeviceId(android::String16 * id)387 android::binder::Status Manager::getDeviceId(android::String16* id) {
388 *id = weaved::binder_utils::ToString16(device_id_);
389 return android::binder::Status::ok();
390 }
391
getDeviceName(android::String16 * name)392 android::binder::Status Manager::getDeviceName(android::String16* name) {
393 *name = weaved::binder_utils::ToString16(device_name_);
394 return android::binder::Status::ok();
395 }
396
getDeviceDescription(android::String16 * description)397 android::binder::Status Manager::getDeviceDescription(
398 android::String16* description) {
399 *description = weaved::binder_utils::ToString16(device_description_);
400 return android::binder::Status::ok();
401 }
402
getDeviceLocation(android::String16 * location)403 android::binder::Status Manager::getDeviceLocation(
404 android::String16* location) {
405 *location = weaved::binder_utils::ToString16(device_location_);
406 return android::binder::Status::ok();
407 }
408
getOemName(android::String16 * name)409 android::binder::Status Manager::getOemName(android::String16* name) {
410 *name = weaved::binder_utils::ToString16(oem_name_);
411 return android::binder::Status::ok();
412 }
413
getModelName(android::String16 * name)414 android::binder::Status Manager::getModelName(android::String16* name) {
415 *name = weaved::binder_utils::ToString16(model_name_);
416 return android::binder::Status::ok();
417 }
418
getModelId(android::String16 * id)419 android::binder::Status Manager::getModelId(android::String16* id) {
420 *id = weaved::binder_utils::ToString16(model_id_);
421 return android::binder::Status::ok();
422 }
423
getPairingSessionId(android::String16 * id)424 android::binder::Status Manager::getPairingSessionId(android::String16* id) {
425 *id = weaved::binder_utils::ToString16(pairing_session_id_);
426 return android::binder::Status::ok();
427 }
428
getPairingMode(android::String16 * mode)429 android::binder::Status Manager::getPairingMode(android::String16* mode) {
430 *mode = weaved::binder_utils::ToString16(pairing_mode_);
431 return android::binder::Status::ok();
432 }
433
getPairingCode(android::String16 * code)434 android::binder::Status Manager::getPairingCode(android::String16* code) {
435 *code = weaved::binder_utils::ToString16(pairing_code_);
436 return android::binder::Status::ok();
437 }
438
getState(android::String16 * state)439 android::binder::Status Manager::getState(android::String16* state) {
440 *state = weaved::binder_utils::ToString16(state_);
441 return android::binder::Status::ok();
442 }
443
getTraits(android::String16 * traits)444 android::binder::Status Manager::getTraits(android::String16* traits) {
445 *traits = weaved::binder_utils::ToString16(device_->GetTraits());
446 return android::binder::Status::ok();
447 }
448
getComponents(android::String16 * components)449 android::binder::Status Manager::getComponents(android::String16* components) {
450 *components = weaved::binder_utils::ToString16(device_->GetComponents());
451 return android::binder::Status::ok();
452 }
453
CreateServicesForClients()454 void Manager::CreateServicesForClients() {
455 CHECK(device_);
456 // For safety, iterate over a copy of |pending_clients_| and clear the
457 // original vector before performing the iterations.
458 std::vector<android::sp<android::weave::IWeaveClient>> pending_clients_copy;
459 std::swap(pending_clients_copy, pending_clients_);
460 for (const auto& client : pending_clients_copy) {
461 android::sp<BinderWeaveService> service =
462 new BinderWeaveService{device_.get(), client};
463 services_.emplace(client, service);
464 client->onServiceConnected(service);
465 android::BinderWrapper::Get()->RegisterForDeathNotifications(
466 android::IInterface::asBinder(client),
467 base::Bind(&Manager::OnClientDisconnected,
468 weak_ptr_factory_.GetWeakPtr(),
469 client));
470 }
471 }
472
OnClientDisconnected(const android::sp<android::weave::IWeaveClient> & client)473 void Manager::OnClientDisconnected(
474 const android::sp<android::weave::IWeaveClient>& client) {
475 services_.erase(client);
476 }
477
OnNotificationListenerDestroyed(const WeaveServiceManagerNotificationListener & notification_listener)478 void Manager::OnNotificationListenerDestroyed(
479 const WeaveServiceManagerNotificationListener& notification_listener) {
480 notification_listeners_.erase(notification_listener);
481 }
482
NotifyServiceManagerChange(const std::vector<int> & notification_ids)483 void Manager::NotifyServiceManagerChange(
484 const std::vector<int>& notification_ids) {
485 if (notification_ids.empty())
486 return;
487 for (const auto& listener : notification_listeners_)
488 listener->notifyServiceManagerChange(notification_ids);
489 }
490
491 } // namespace buffet
492