Home | History | Annotate | Download | only in buffet
      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 
     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 
     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 
     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 
    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 
    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.
    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:
    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 
    176 Manager::Manager(const Options& options,
    177                  const scoped_refptr<dbus::Bus>& bus)
    178     : options_{options}, bus_{bus} {}
    179 
    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 
    192 void Manager::Start(AsyncEventSequencer* sequencer) {
    193   power_manager_client_.Init();
    194   RestartWeave(sequencer);
    195 }
    196 
    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 
    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 
    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 
    285 void Manager::OnTraitDefsChanged() {
    286   NotifyServiceManagerChange({NotificationListener::TRAITS});
    287 }
    288 
    289 void Manager::OnComponentTreeChanged() {
    290   NotifyServiceManagerChange({NotificationListener::COMPONENTS});
    291 }
    292 
    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 
    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 
    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 
    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 
    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 
    360 void Manager::RebootDeviceNow() {
    361   power_manager_client_.Reboot(android::RebootReason::DEFAULT);
    362 }
    363 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    439 android::binder::Status Manager::getState(android::String16* state) {
    440   *state = weaved::binder_utils::ToString16(state_);
    441   return android::binder::Status::ok();
    442 }
    443 
    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 
    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 
    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 
    473 void Manager::OnClientDisconnected(
    474     const android::sp<android::weave::IWeaveClient>& client) {
    475   services_.erase(client);
    476 }
    477 
    478 void Manager::OnNotificationListenerDestroyed(
    479     const WeaveServiceManagerNotificationListener& notification_listener) {
    480   notification_listeners_.erase(notification_listener);
    481 }
    482 
    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