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
53using brillo::dbus_utils::AsyncEventSequencer;
54using NotificationListener =
55    android::weave::IWeaveServiceManagerNotificationListener;
56
57namespace buffet {
58
59namespace {
60
61const char kErrorDomain[] = "buffet";
62const char kFileReadError[] = "file_read_error";
63const char kBaseComponent[] = "base";
64const char kRebootCommand[] = "base.reboot";
65
66bool 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
79void 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
96void 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
117void 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
134void 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.
154void 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
167class Manager::TaskRunner : public weave::provider::TaskRunner {
168 public:
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
176Manager::Manager(const Options& options,
177                 const scoped_refptr<dbus::Bus>& bus)
178    : options_{options}, bus_{bus} {}
179
180Manager::~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
192void Manager::Start(AsyncEventSequencer* sequencer) {
193  power_manager_client_.Init();
194  RestartWeave(sequencer);
195}
196
197void 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
232void 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
273void 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
285void Manager::OnTraitDefsChanged() {
286  NotifyServiceManagerChange({NotificationListener::TRAITS});
287}
288
289void Manager::OnComponentTreeChanged() {
290  NotifyServiceManagerChange({NotificationListener::COMPONENTS});
291}
292
293void 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
299void 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
320void 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
336void 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
349void 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
360void Manager::RebootDeviceNow() {
361  power_manager_client_.Reboot(android::RebootReason::DEFAULT);
362}
363
364android::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
372android::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
382android::binder::Status Manager::getCloudId(android::String16* id) {
383  *id = weaved::binder_utils::ToString16(cloud_id_);
384  return android::binder::Status::ok();
385}
386
387android::binder::Status Manager::getDeviceId(android::String16* id) {
388  *id = weaved::binder_utils::ToString16(device_id_);
389  return android::binder::Status::ok();
390}
391
392android::binder::Status Manager::getDeviceName(android::String16* name) {
393  *name = weaved::binder_utils::ToString16(device_name_);
394  return android::binder::Status::ok();
395}
396
397android::binder::Status Manager::getDeviceDescription(
398    android::String16* description) {
399  *description = weaved::binder_utils::ToString16(device_description_);
400  return android::binder::Status::ok();
401}
402
403android::binder::Status Manager::getDeviceLocation(
404    android::String16* location) {
405  *location = weaved::binder_utils::ToString16(device_location_);
406  return android::binder::Status::ok();
407}
408
409android::binder::Status Manager::getOemName(android::String16* name) {
410  *name = weaved::binder_utils::ToString16(oem_name_);
411  return android::binder::Status::ok();
412}
413
414android::binder::Status Manager::getModelName(android::String16* name) {
415  *name = weaved::binder_utils::ToString16(model_name_);
416  return android::binder::Status::ok();
417}
418
419android::binder::Status Manager::getModelId(android::String16* id) {
420  *id = weaved::binder_utils::ToString16(model_id_);
421  return android::binder::Status::ok();
422}
423
424android::binder::Status Manager::getPairingSessionId(android::String16* id) {
425  *id = weaved::binder_utils::ToString16(pairing_session_id_);
426  return android::binder::Status::ok();
427}
428
429android::binder::Status Manager::getPairingMode(android::String16* mode) {
430  *mode = weaved::binder_utils::ToString16(pairing_mode_);
431  return android::binder::Status::ok();
432}
433
434android::binder::Status Manager::getPairingCode(android::String16* code) {
435  *code = weaved::binder_utils::ToString16(pairing_code_);
436  return android::binder::Status::ok();
437}
438
439android::binder::Status Manager::getState(android::String16* state) {
440  *state = weaved::binder_utils::ToString16(state_);
441  return android::binder::Status::ok();
442}
443
444android::binder::Status Manager::getTraits(android::String16* traits) {
445  *traits = weaved::binder_utils::ToString16(device_->GetTraits());
446  return android::binder::Status::ok();
447}
448
449android::binder::Status Manager::getComponents(android::String16* components) {
450  *components = weaved::binder_utils::ToString16(device_->GetComponents());
451  return android::binder::Status::ok();
452}
453
454void 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
473void Manager::OnClientDisconnected(
474    const android::sp<android::weave::IWeaveClient>& client) {
475  services_.erase(client);
476}
477
478void Manager::OnNotificationListenerDestroyed(
479    const WeaveServiceManagerNotificationListener& notification_listener) {
480  notification_listeners_.erase(notification_listener);
481}
482
483void 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