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