blob: ab247345dfc38263c3df55e83a24626ed16164e9 [file] [log] [blame]
/******************************************************************************
*
* 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 <hardware/bluetooth.h>
#if defined(STATIC_LIBBLUETOOTH)
#include <cstdlib>
#include <cstring>
#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; }