/****************************************************************************** * * Copyright 2014 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. * ******************************************************************************/ #define LOG_TAG "bt_stack_manager" #include "stack_manager.h" #include #if defined(STATIC_LIBBLUETOOTH) #include #include #endif #include "btcore/include/module.h" #include "btcore/include/osi_module.h" #include "btif_api.h" #include "btif_common.h" #include "common/message_loop_thread.h" #include "device/include/controller.h" #include "hci/include/btsnoop.h" #include "main/shim/shim.h" #include "osi/include/log.h" #include "osi/include/osi.h" #include "osi/include/semaphore.h" #include "stack/include/acl_api.h" #include "stack/include/btm_client_interface.h" #include "stack/include/btu.h" // Temp includes #include "bt_utils.h" #include "bta/sys/bta_sys.h" #include "btif_config.h" #include "btif_profile_queue.h" #include "internal_include/bt_target.h" #include "internal_include/bte.h" #include "stack/include/gatt_api.h" #include "stack/include/l2c_api.h" #include "stack/include/port_api.h" #include "stack/sdp/sdpint.h" #if (BNEP_INCLUDED == TRUE) #include "stack/include/bnep_api.h" #endif #include "stack/include/gap_api.h" #if (PAN_INCLUDED == TRUE) #include "stack/include/pan_api.h" #endif #include "stack/include/a2dp_api.h" #include "stack/include/avrc_api.h" #if (HID_HOST_INCLUDED == TRUE) #include "stack/include/hidh_api.h" #endif #include "stack/include/smp_api.h" #include "bta_ar_api.h" #include "bta/sys/bta_sys_int.h" #include "bta_dm_int.h" #include "btif/include/btif_pan.h" #include "btif/include/btif_sock.h" #include "device/include/interop.h" #include "internal_include/stack_config.h" #include "main/shim/controller.h" void main_thread_shut_down(); void main_thread_start_up(); void BTA_dm_on_hw_on(); void BTA_dm_on_hw_off(); using bluetooth::common::MessageLoopThread; static MessageLoopThread management_thread("bt_stack_manager_thread"); // If initialized, any of the bluetooth API functions can be called. // (e.g. turning logging on and off, enabling/disabling the stack, etc) static bool stack_is_initialized; // If running, the stack is fully up and able to bluetooth. static bool stack_is_running; static void event_init_stack(void* context); static void event_start_up_stack(void* context); static void event_shut_down_stack(void* context); static void event_clean_up_stack(void* context); static void event_signal_stack_up(void* context); static void event_signal_stack_down(void* context); // Unvetted includes/imports, etc which should be removed or vetted in the // future static future_t* hack_future; // End unvetted section // Interface functions static void init_stack() { // This is a synchronous process. Post it to the thread though, so // state modification only happens there. Using the thread to perform // all stack operations ensures that the operations are done serially // and do not overlap. semaphore_t* semaphore = semaphore_new(0); management_thread.DoInThread(FROM_HERE, base::Bind(event_init_stack, semaphore)); semaphore_wait(semaphore); semaphore_free(semaphore); } static void start_up_stack_async() { management_thread.DoInThread(FROM_HERE, base::Bind(event_start_up_stack, nullptr)); } static void shut_down_stack_async() { management_thread.DoInThread(FROM_HERE, base::Bind(event_shut_down_stack, nullptr)); } static void clean_up_stack() { // This is a synchronous process. Post it to the thread though, so // state modification only happens there. semaphore_t* semaphore = semaphore_new(0); management_thread.DoInThread(FROM_HERE, base::Bind(event_clean_up_stack, semaphore)); semaphore_wait(semaphore); semaphore_free(semaphore); management_thread.ShutDown(); } static bool get_stack_is_running() { return stack_is_running; } // Internal functions #ifdef STATIC_LIBBLUETOOTH extern const module_t bt_utils_module; extern const module_t bte_logmsg_module; extern const module_t btif_config_module; extern const module_t btsnoop_module; extern const module_t bt_utils_module; extern const module_t controller_module; extern const module_t gd_idle_module; extern const module_t gd_shim_module; extern const module_t hci_module; extern const module_t interop_module; extern const module_t osi_module; extern const module_t stack_config_module; struct module_lookup { const char* name; const module_t* module; }; const struct module_lookup module_table[] = { {BTE_LOGMSG_MODULE, &bte_logmsg_module}, {BTIF_CONFIG_MODULE, &btif_config_module}, {BTSNOOP_MODULE, &btsnoop_module}, {BT_UTILS_MODULE, &bt_utils_module}, {CONTROLLER_MODULE, &controller_module}, {GD_IDLE_MODULE, &gd_idle_module}, {GD_SHIM_MODULE, &gd_shim_module}, {HCI_MODULE, &hci_module}, {INTEROP_MODULE, &interop_module}, {OSI_MODULE, &osi_module}, {STACK_CONFIG_MODULE, &stack_config_module}, {NULL, NULL}, }; inline const module_t* get_local_module(const char* name) { size_t len = strlen(name); for (const struct module_lookup* l = module_table; l->module; l++) { if (strncmp(l->name, name, len) == 0) { return l->module; } } abort(); return nullptr; } #else inline const module_t* get_local_module(const char* name) { return get_module(name); } #endif // Synchronous function to initialize the stack static void event_init_stack(void* context) { semaphore_t* semaphore = (semaphore_t*)context; LOG_INFO("is initializing the stack"); if (stack_is_initialized) { LOG_INFO("found the stack already in initialized state"); } else { module_management_start(); module_init(get_local_module(OSI_MODULE)); module_init(get_local_module(BT_UTILS_MODULE)); if (bluetooth::shim::is_any_gd_enabled()) { module_start_up(get_local_module(GD_IDLE_MODULE)); } module_init(get_local_module(BTIF_CONFIG_MODULE)); btif_init_bluetooth(); module_init(get_local_module(INTEROP_MODULE)); bte_main_init(); module_init(get_local_module(STACK_CONFIG_MODULE)); // stack init is synchronous, so no waiting necessary here stack_is_initialized = true; } LOG_INFO("finished"); if (semaphore) semaphore_post(semaphore); } static void ensure_stack_is_initialized() { if (!stack_is_initialized) { LOG_WARN("%s found the stack was uninitialized. Initializing now.", __func__); // No semaphore needed since we are calling it directly event_init_stack(nullptr); } } // Synchronous function to start up the stack static void event_start_up_stack(UNUSED_ATTR void* context) { if (stack_is_running) { LOG_INFO("%s stack already brought up", __func__); return; } ensure_stack_is_initialized(); LOG_INFO("%s is bringing up the stack", __func__); future_t* local_hack_future = future_new(); hack_future = local_hack_future; if (bluetooth::shim::is_any_gd_enabled()) { LOG_INFO("%s Gd shim module enabled", __func__); module_shut_down(get_local_module(GD_IDLE_MODULE)); module_start_up(get_local_module(GD_SHIM_MODULE)); module_start_up(get_local_module(BTIF_CONFIG_MODULE)); } else { module_start_up(get_local_module(BTIF_CONFIG_MODULE)); module_start_up(get_local_module(BTSNOOP_MODULE)); module_start_up(get_local_module(HCI_MODULE)); } get_btm_client_interface().lifecycle.btm_init(); l2c_init(); sdp_init(); gatt_init(); SMP_Init(); get_btm_client_interface().lifecycle.btm_ble_init(); RFCOMM_Init(); #if (BNEP_INCLUDED == TRUE) BNEP_Init(); #if (PAN_INCLUDED == TRUE) PAN_Init(); #endif /* PAN */ #endif /* BNEP Included */ A2DP_Init(); AVRC_Init(); GAP_Init(); #if (HID_HOST_INCLUDED == TRUE) HID_HostInit(); #endif bta_sys_init(); bta_ar_init(); module_init(get_local_module(BTE_LOGMSG_MODULE)); main_thread_start_up(); btif_init_ok(); BTA_dm_init(); bta_dm_enable(bte_dm_evt); bta_set_forward_hw_failures(true); btm_acl_device_down(); if (bluetooth::shim::is_gd_controller_enabled()) { CHECK(module_start_up(get_local_module(GD_CONTROLLER_MODULE))); } else { CHECK(module_start_up(get_local_module(CONTROLLER_MODULE))); } BTM_reset_complete(); BTA_dm_on_hw_on(); if (future_await(local_hack_future) != FUTURE_SUCCESS) { LOG_ERROR("%s failed to start up the stack", __func__); stack_is_running = true; // So stack shutdown actually happens event_shut_down_stack(nullptr); return; } stack_is_running = true; LOG_INFO("%s finished", __func__); do_in_jni_thread(FROM_HERE, base::Bind(event_signal_stack_up, nullptr)); } // Synchronous function to shut down the stack static void event_shut_down_stack(UNUSED_ATTR void* context) { if (!stack_is_running) { LOG_INFO("%s stack is already brought down", __func__); return; } LOG_INFO("%s is bringing down the stack", __func__); future_t* local_hack_future = future_new(); hack_future = local_hack_future; stack_is_running = false; do_in_main_thread(FROM_HERE, base::Bind(&btm_ble_multi_adv_cleanup)); btif_dm_on_disable(); btif_sock_cleanup(); btif_pan_cleanup(); do_in_main_thread(FROM_HERE, base::Bind(bta_dm_disable)); future_await(local_hack_future); local_hack_future = future_new(); hack_future = local_hack_future; bta_sys_disable(); bta_set_forward_hw_failures(false); BTA_dm_on_hw_off(); module_shut_down(get_local_module(BTIF_CONFIG_MODULE)); future_await(local_hack_future); main_thread_shut_down(); module_clean_up(get_local_module(BTE_LOGMSG_MODULE)); gatt_free(); l2c_free(); sdp_free(); get_btm_client_interface().lifecycle.btm_ble_free(); get_btm_client_interface().lifecycle.btm_free(); if (bluetooth::shim::is_any_gd_enabled()) { LOG_INFO("%s Gd shim module disabled", __func__); module_shut_down(get_local_module(GD_SHIM_MODULE)); module_start_up(get_local_module(GD_IDLE_MODULE)); } else { module_shut_down(get_local_module(HCI_MODULE)); module_shut_down(get_local_module(BTSNOOP_MODULE)); } module_shut_down( get_local_module(CONTROLLER_MODULE)); // Doesn't do any work, just // puts it in a restartable // state hack_future = future_new(); do_in_jni_thread(FROM_HERE, base::Bind(event_signal_stack_down, nullptr)); future_await(hack_future); LOG_INFO("%s finished", __func__); } static void ensure_stack_is_not_running() { if (stack_is_running) { LOG_WARN("%s found the stack was still running. Bringing it down now.", __func__); event_shut_down_stack(nullptr); } } // Synchronous function to clean up the stack static void event_clean_up_stack(void* context) { if (!stack_is_initialized) { LOG_INFO("%s found the stack already in a clean state", __func__); goto cleanup; } ensure_stack_is_not_running(); LOG_INFO("%s is cleaning up the stack", __func__); stack_is_initialized = false; btif_cleanup_bluetooth(); module_clean_up(get_local_module(STACK_CONFIG_MODULE)); module_clean_up(get_local_module(INTEROP_MODULE)); module_clean_up(get_local_module(BTIF_CONFIG_MODULE)); module_clean_up(get_local_module(BT_UTILS_MODULE)); module_clean_up(get_local_module(OSI_MODULE)); module_shut_down(get_local_module(GD_IDLE_MODULE)); module_management_stop(); LOG_INFO("%s finished", __func__); cleanup:; semaphore_t* semaphore = (semaphore_t*)context; if (semaphore) semaphore_post(semaphore); } static void event_signal_stack_up(UNUSED_ATTR void* context) { // Notify BTIF connect queue that we've brought up the stack. It's // now time to dispatch all the pending profile connect requests. btif_queue_connect_next(); invoke_adapter_state_changed_cb(BT_STATE_ON); } static void event_signal_stack_down(UNUSED_ATTR void* context) { invoke_adapter_state_changed_cb(BT_STATE_OFF); future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS); } static void ensure_manager_initialized() { if (management_thread.IsRunning()) return; management_thread.StartUp(); if (!management_thread.IsRunning()) { LOG_ERROR("%s unable to start stack management thread", __func__); return; } } static const stack_manager_t interface = {init_stack, start_up_stack_async, shut_down_stack_async, clean_up_stack, get_stack_is_running}; const stack_manager_t* stack_manager_get_interface() { ensure_manager_initialized(); return &interface; } future_t* stack_manager_get_hack_future() { return hack_future; }