| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "bluetooth/newblued/newblue_daemon.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include <sysexits.h> |
| |
| #include <base/logging.h> |
| #include <base/threading/platform_thread.h> |
| #include <chromeos/dbus/service_constants.h> |
| |
| #include "bluetooth/common/dbus_daemon.h" |
| |
| namespace bluetooth { |
| |
| NewblueDaemon::NewblueDaemon(std::unique_ptr<Newblue> newblue, |
| bool is_idle_mode) |
| : is_idle_mode_(is_idle_mode), |
| newblue_(std::move(newblue)), |
| weak_ptr_factory_(this) {} |
| |
| bool NewblueDaemon::Init(scoped_refptr<dbus::Bus> bus, |
| DBusDaemon* dbus_daemon) { |
| bus_ = bus; |
| dbus_daemon_ = dbus_daemon; |
| |
| if (!bus_->RequestOwnershipAndBlock( |
| newblue_object_manager::kNewblueObjectManagerServiceName, |
| dbus::Bus::REQUIRE_PRIMARY)) { |
| LOG(ERROR) << "Failed to acquire D-Bus name ownership: " |
| << newblue_object_manager::kNewblueObjectManagerServiceName; |
| } |
| |
| if (is_idle_mode_) { |
| LOG(INFO) << "LE splitter not enabled, newblued running in idle mode."; |
| LOG(INFO) << "To enable, run 'newblue enable' in crosh and reboot."; |
| return true; |
| } |
| |
| auto exported_object_manager = |
| std::make_unique<brillo::dbus_utils::ExportedObjectManager>( |
| bus_, dbus::ObjectPath( |
| newblue_object_manager::kNewblueObjectManagerServicePath)); |
| |
| exported_object_manager_wrapper_ = |
| std::make_unique<ExportedObjectManagerWrapper>( |
| bus_, std::move(exported_object_manager)); |
| |
| if (!newblue_->Init()) { |
| LOG(ERROR) << "Failed initializing NewBlue"; |
| return false; |
| } |
| |
| adapter_interface_handler_ = std::make_unique<AdapterInterfaceHandler>( |
| bus_, exported_object_manager_wrapper_.get()); |
| device_interface_handler_ = std::make_unique<DeviceInterfaceHandler>( |
| bus_, newblue_.get(), exported_object_manager_wrapper_.get()); |
| advertising_manager_interface_handler_ = |
| std::make_unique<AdvertisingManagerInterfaceHandler>( |
| newblue_->libnewblue(), bus_, exported_object_manager_wrapper_.get()); |
| agent_manager_interface_handler_ = |
| std::make_unique<AgentManagerInterfaceHandler>( |
| bus_, exported_object_manager_wrapper_.get()); |
| debug_manager_ = std::make_unique<NewblueDebugManager>(bus_); |
| |
| debug_manager_->Init(); |
| agent_manager_interface_handler_->Init(); |
| newblue_->RegisterPairingAgent(agent_manager_interface_handler_.get()); |
| |
| gatt_ = |
| std::make_unique<Gatt>(newblue_.get(), device_interface_handler_.get()); |
| gatt_interface_handler_ = std::make_unique<GattInterfaceHandler>( |
| bus_, newblue_.get(), exported_object_manager_wrapper_.get(), |
| gatt_.get()); |
| gatt_interface_handler_->Init(); |
| |
| if (!newblue_->ListenReadyForUp(base::Bind(&NewblueDaemon::OnHciReadyForUp, |
| base::Unretained(this)))) { |
| LOG(ERROR) << "Error listening to HCI ready for up"; |
| return false; |
| } |
| |
| LOG(INFO) << "newblued initialized"; |
| return true; |
| } |
| |
| void NewblueDaemon::Shutdown() { |
| newblue_->UnregisterPairingAgent(); |
| |
| gatt_.reset(); |
| |
| newblue_.reset(); |
| agent_manager_interface_handler_.reset(); |
| device_interface_handler_.reset(); |
| exported_object_manager_wrapper_.reset(); |
| debug_manager_.reset(); |
| } |
| |
| void NewblueDaemon::OnHciReadyForUp() { |
| VLOG(1) << "NewBlue ready for up"; |
| |
| // Workaround to avoid immediately bringing up the stack as this may result |
| // in chip hang. |
| // TODO(sonnysasaka): Remove this sleep when the kernel LE splitter bug |
| // is fixed(https://crbug.com/852446). |
| base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); |
| |
| if (!newblue_->BringUp()) { |
| LOG(ERROR) << "error bringing up NewBlue"; |
| dbus_daemon_->QuitWithExitCode(EX_UNAVAILABLE); |
| return; |
| } |
| adapter_interface_handler_->Init(device_interface_handler_.get(), |
| newblue_.get()); |
| stack_sync_monitor_.RegisterBluezDownCallback( |
| bus_.get(), |
| base::Bind(&NewblueDaemon::OnBluezDown, weak_ptr_factory_.GetWeakPtr())); |
| LOG(INFO) << "NewBlue is up"; |
| |
| advertising_manager_interface_handler_->Init(); |
| |
| if (!device_interface_handler_->Init()) { |
| LOG(ERROR) << "Failed to initialize device interface"; |
| dbus_daemon_->QuitWithExitCode(EX_UNAVAILABLE); |
| return; |
| } |
| } |
| |
| void NewblueDaemon::OnBluezDown() { |
| ExportedInterface* adapter_interface = |
| exported_object_manager_wrapper_->GetExportedInterface( |
| dbus::ObjectPath(kAdapterObjectPath), |
| bluetooth_adapter::kBluetoothAdapterInterface); |
| if (!adapter_interface) |
| return; |
| |
| LOG(INFO) << "Quitting due to BlueZ down detected"; |
| adapter_interface |
| ->EnsureExportedPropertyRegistered<bool>( |
| bluetooth_adapter::kStackSyncQuittingProperty) |
| ->SetValue(true); |
| exit(0); // TODO(crbug/873905): Quit gracefully after this is fixed. |
| } |
| |
| } // namespace bluetooth |