| // |
| // Copyright (C) 2015 Google, Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at: |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| #include "core_stack.h" |
| |
| #include <signal.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <time.h> |
| |
| #include <condition_variable> |
| #include <mutex> |
| #include <string> |
| |
| #include <hardware/bluetooth.h> |
| #include <hardware/hardware.h> |
| |
| // TODO(armansito): Remove this line and use base/logging.h instead. |
| #define LOG_TAG "bluetooth_daemon" |
| |
| #include "logging_helpers.h" |
| |
| extern "C" { |
| #include "btcore/include/hal_util.h" |
| #include "osi/include/log.h" |
| #include "osi/include/osi.h" |
| } // extern "C" |
| |
| namespace { |
| |
| std::mutex mutex; |
| std::condition_variable synchronize; |
| bool instantiated = false; |
| |
| void AdapterStateChangedCallback(bt_state_t state) { |
| LOG_INFO(LOG_TAG, "Bluetooth state:%s", BtStateText(state)); |
| std::lock_guard<std::mutex> lock(mutex); |
| synchronize.notify_one(); |
| } |
| |
| void CallbackThreadCallback(bt_cb_thread_evt evt) { |
| LOG_INFO(LOG_TAG, "%s: %s", __func__, BtEventText(evt)); |
| } |
| |
| // TODO(icoolidge): Audit how these os callouts should be |
| // implemented (or nulled) for systems w/out wakelocks. |
| bool SetWakeAlarmCallback(uint64_t delay_millis, |
| UNUSED_ATTR bool should_wake, |
| alarm_cb cb, |
| void *data) { |
| static timer_t timer; |
| static bool timer_created; |
| |
| if (!timer_created) { |
| struct sigevent sigevent; |
| memset(&sigevent, 0, sizeof(sigevent)); |
| sigevent.sigev_notify = SIGEV_THREAD; |
| sigevent.sigev_notify_function = (void (*)(union sigval))cb; |
| sigevent.sigev_value.sival_ptr = data; |
| timer_create(CLOCK_MONOTONIC, &sigevent, &timer); |
| timer_created = true; |
| } |
| |
| struct itimerspec new_value; |
| new_value.it_value.tv_sec = delay_millis / 1000; |
| new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000; |
| new_value.it_interval.tv_sec = 0; |
| new_value.it_interval.tv_nsec = 0; |
| timer_settime(timer, 0, &new_value, nullptr); |
| |
| return true; |
| } |
| |
| // Dummy implementation due to no wakelocks. |
| int AcquireWakeLock(UNUSED_ATTR const char *lock_name) { |
| return BT_STATUS_SUCCESS; |
| } |
| |
| // Dummy implementation due to no wakelocks. |
| int ReleaseWakeLock(UNUSED_ATTR const char *lock_name) { |
| return BT_STATUS_SUCCESS; |
| } |
| |
| void GenericDevicePropertiesCallback(bt_status_t status, |
| bt_bdaddr_t *remote_address, |
| int num_properties, |
| bt_property_t *properties) { |
| if (status != BT_STATUS_SUCCESS) { |
| LOG_ERROR(LOG_TAG, "%s: %s", __func__, BtStatusText(status)); |
| return; |
| } |
| |
| if (!remote_address) { |
| LOG_INFO(LOG_TAG, "%s", "Local adapter properties:"); |
| } |
| |
| for (int i = 0; i < num_properties; ++i) { |
| bt_property_t *prop = &properties[i]; |
| switch (prop->type) { |
| case BT_PROPERTY_BDADDR: { |
| std::string text = |
| BtAddrString(reinterpret_cast<bt_bdaddr_t *>(prop->val)); |
| LOG_INFO(LOG_TAG, "%s: %s", BtPropertyText(prop->type), text.c_str()); |
| break; |
| } |
| case BT_PROPERTY_ADAPTER_SCAN_MODE: { |
| bt_scan_mode_t *mode = reinterpret_cast<bt_scan_mode_t *>(prop->val); |
| LOG_INFO(LOG_TAG, "%s: %s", BtPropertyText(prop->type), BtScanModeText(*mode)); |
| std::lock_guard<std::mutex> lock(mutex); |
| synchronize.notify_one(); |
| break; |
| } |
| case BT_PROPERTY_BDNAME: { |
| bt_bdname_t *name = reinterpret_cast<bt_bdname_t *>(prop->val); |
| LOG_INFO(LOG_TAG, "%s: %s", BtPropertyText(prop->type), |
| reinterpret_cast<char *>(name->name)); |
| std::lock_guard<std::mutex> lock(mutex); |
| synchronize.notify_one(); |
| break; |
| } |
| default: |
| LOG_INFO(LOG_TAG, "%s: %s", __func__, BtPropertyText(prop->type)); |
| break; |
| } |
| } |
| } |
| |
| void AclStateChangedCallback(bt_status_t status, bt_bdaddr_t *remote_bd_addr, |
| bt_acl_state_t state) { |
| if (status != BT_STATUS_SUCCESS) { |
| LOG_ERROR(LOG_TAG, "%s: %s", __func__, BtStatusText(status)); |
| return; |
| } |
| |
| std::string text = BtAddrString(remote_bd_addr); |
| LOG_INFO(LOG_TAG, "%s: %s: %s", __func__, text.c_str(), BtAclText(state)); |
| } |
| |
| void LocalAdapterPropertiesCallback(bt_status_t status, int num_properties, |
| bt_property_t *properties) { |
| GenericDevicePropertiesCallback(status, nullptr, num_properties, properties); |
| } |
| |
| bt_callbacks_t bt_callbacks = { |
| sizeof(bt_callbacks_t), |
| AdapterStateChangedCallback, |
| LocalAdapterPropertiesCallback, |
| GenericDevicePropertiesCallback, |
| nullptr, /* device_found_cb */ |
| nullptr, /* discovery_state_changed_cb */ |
| nullptr, /* pin_request_cb */ |
| nullptr, /* ssp_request_cb */ |
| nullptr, /* bond_state_changed_cb */ |
| AclStateChangedCallback, |
| CallbackThreadCallback, |
| nullptr, /* dut_mode_recv_cb */ |
| nullptr, /* le_test_mode_cb */ |
| nullptr /* energy_info_cb */ |
| }; |
| |
| bt_os_callouts_t callouts = { |
| sizeof(bt_os_callouts_t), |
| SetWakeAlarmCallback, |
| AcquireWakeLock, |
| ReleaseWakeLock |
| }; |
| |
| } // namespace |
| |
| namespace bluetooth { |
| |
| // The real CoreStack implementation to be used in production code. |
| class CoreStackImpl : public CoreStack { |
| public: |
| CoreStackImpl(); |
| ~CoreStackImpl() override; |
| |
| // CoreStack overrides. |
| bool Initialize() override; |
| bool SetAdapterName(const std::string& name) override; |
| bool SetClassicDiscoverable() override; |
| const void* GetInterface(const char* profile) override; |
| |
| private: |
| // Our libhardware handle. |
| bluetooth_device_t *adapter_; |
| |
| // Common Bluetooth interface handle. |
| const bt_interface_t *hal_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CoreStackImpl); |
| }; |
| |
| CoreStackImpl::CoreStackImpl() : adapter_(nullptr), hal_(nullptr) { |
| std::lock_guard<std::mutex> lock(mutex); |
| // TODO(icoolidge): DCHECK(!instantiated); |
| instantiated = true; |
| } |
| |
| bool CoreStackImpl::Initialize() { |
| std::unique_lock<std::mutex> lock(mutex); |
| |
| // Load the bluetooth module. |
| const hw_module_t *module; |
| int status = hal_util_load_bt_library(&module); |
| if (status) { |
| LOG_ERROR(LOG_TAG, "Error getting bluetooth module"); |
| return false; |
| } |
| |
| // Open the bluetooth device. |
| hw_device_t *device; |
| status = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device); |
| if (status) { |
| LOG_ERROR(LOG_TAG, "Error opening bluetooth module"); |
| return false; |
| } |
| |
| // TODO(icoolidge): Audit initialization and teardown. |
| adapter_ = reinterpret_cast<bluetooth_device_t *>(device); |
| hal_ = adapter_->get_bluetooth_interface(); |
| |
| // Bind module callbacks to local handlers. |
| status = hal_->init(&bt_callbacks); |
| if (status != BT_STATUS_SUCCESS) { |
| LOG_ERROR(LOG_TAG, "Error binding callbacks"); |
| return false; |
| } |
| |
| status = hal_->set_os_callouts(&callouts); |
| if (status != BT_STATUS_SUCCESS) { |
| LOG_ERROR(LOG_TAG, "Error binding OS callbacks"); |
| return false; |
| } |
| |
| status = hal_->enable(); |
| if (status) { |
| LOG_ERROR(LOG_TAG, "Enable failed: %d", status); |
| return false; |
| } |
| |
| synchronize.wait(lock); |
| LOG_INFO(LOG_TAG, "%s", "CoreStackImpl::Initialize success"); |
| return true; |
| } |
| |
| bool CoreStackImpl::SetAdapterName(const std::string &name) { |
| bt_bdname_t n; |
| snprintf(reinterpret_cast<char *>(n.name), sizeof(n.name), "%s", |
| name.c_str()); |
| bt_property_t prop; |
| prop.len = sizeof(n); |
| prop.val = &n; |
| prop.type = BT_PROPERTY_BDNAME; |
| |
| std::unique_lock<std::mutex> lock(mutex); |
| |
| int status = hal_->set_adapter_property(&prop); |
| if (status) { |
| LOG_ERROR(LOG_TAG, "%s: prop change failed: %d", __func__, status); |
| return false; |
| } |
| |
| synchronize.wait(lock); |
| return true; |
| } |
| |
| bool CoreStackImpl::SetClassicDiscoverable() { |
| bt_scan_mode_t mode = BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE; |
| bt_property_t disc; |
| disc.len = sizeof(mode); |
| disc.val = &mode; |
| disc.type = BT_PROPERTY_ADAPTER_SCAN_MODE; |
| |
| std::unique_lock<std::mutex> lock(mutex); |
| |
| int status = hal_->set_adapter_property(&disc); |
| if (status) { |
| LOG_ERROR(LOG_TAG, "Prop change failed: %d", status); |
| return false; |
| } |
| |
| synchronize.wait(lock); |
| return true; |
| } |
| |
| const void* CoreStackImpl::GetInterface(const char *profile) { |
| std::unique_lock<std::mutex> lock(mutex); |
| // Get the interface to the GATT profile. |
| const void *interface = hal_->get_profile_interface(profile); |
| if (!interface) { |
| LOG_ERROR(LOG_TAG, "Error getting %s interface", profile); |
| return nullptr; |
| } |
| return interface; |
| } |
| |
| CoreStackImpl::~CoreStackImpl() { |
| // TODO(icoolidge): Disable bluetooth hardware, clean up library state. |
| std::lock_guard<std::mutex> lock(mutex); |
| instantiated = false; |
| } |
| |
| // static |
| std::unique_ptr<CoreStack> CoreStack::Create() { |
| return std::unique_ptr<CoreStack>(new CoreStackImpl()); |
| } |
| |
| } // namespace bluetooth |