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