/******************************************************************************
*
* Copyright (C) 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>
#include "btcore/include/module.h"
#include "btcore/include/osi_module.h"
#include "btif_api.h"
#include "btif_common.h"
#include "device/include/controller.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "osi/include/semaphore.h"
#include "osi/include/thread.h"
// Temp includes
#include "btif_config.h"
#include "btif_profile_queue.h"
#include "bt_utils.h"
static thread_t *management_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;
void bte_main_enable();
void btif_thread_post(thread_fn func, void *context);
// End unvetted section
// Interface functions
static void init_stack(void) {
// 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);
thread_post(management_thread, event_init_stack, semaphore);
semaphore_wait(semaphore);
semaphore_free(semaphore);
}
static void start_up_stack_async(void) {
thread_post(management_thread, event_start_up_stack, NULL);
}
static void shut_down_stack_async(void) {
thread_post(management_thread, event_shut_down_stack, NULL);
}
static void clean_up_stack(void) {
// This is a synchronous process. Post it to the thread though, so
// state modification only happens there.
semaphore_t *semaphore = semaphore_new(0);
thread_post(management_thread, event_clean_up_stack, semaphore);
semaphore_wait(semaphore);
semaphore_free(semaphore);
}
static bool get_stack_is_running(void) {
return stack_is_running;
}
// Internal functions
// Synchronous function to initialize the stack
static void event_init_stack(void *context) {
semaphore_t *semaphore = (semaphore_t *)context;
LOG_INFO(LOG_TAG, "%s is initializing the stack", __func__);
if (stack_is_initialized) {
LOG_INFO(LOG_TAG, "%s found the stack already in initialized state",
__func__);
} else {
module_management_start();
module_init(get_module(OSI_MODULE));
module_init(get_module(BT_UTILS_MODULE));
module_init(get_module(BTIF_CONFIG_MODULE));
btif_init_bluetooth();
// stack init is synchronous, so no waiting necessary here
stack_is_initialized = true;
}
LOG_INFO(LOG_TAG, "%s finished", __func__);
if (semaphore)
semaphore_post(semaphore);
}
static void ensure_stack_is_initialized(void) {
if (!stack_is_initialized) {
LOG_WARN(LOG_TAG, "%s found the stack was uninitialized. Initializing now.", __func__);
// No semaphore needed since we are calling it directly
event_init_stack(NULL);
}
}
// Synchronous function to start up the stack
static void event_start_up_stack(UNUSED_ATTR void *context) {
if (stack_is_running) {
LOG_INFO(LOG_TAG, "%s stack already brought up", __func__);
return;
}
ensure_stack_is_initialized();
LOG_INFO(LOG_TAG, "%s is bringing up the stack", __func__);
future_t *local_hack_future = future_new();
hack_future = local_hack_future;
// Include this for now to put btif config into a shutdown-able state
module_start_up(get_module(BTIF_CONFIG_MODULE));
bte_main_enable();
if (future_await(local_hack_future) != FUTURE_SUCCESS) {
LOG_ERROR(LOG_TAG, "%s failed to start up the stack", __func__);
stack_is_running = true; // So stack shutdown actually happens
event_shut_down_stack(NULL);
return;
}
stack_is_running = true;
LOG_INFO(LOG_TAG, "%s finished", __func__);
btif_thread_post(event_signal_stack_up, NULL);
}
// Synchronous function to shut down the stack
static void event_shut_down_stack(UNUSED_ATTR void *context) {
if (!stack_is_running) {
LOG_INFO(LOG_TAG, "%s stack is already brought down", __func__);
return;
}
LOG_INFO(LOG_TAG, "%s is bringing down the stack", __func__);
future_t *local_hack_future = future_new();
hack_future = local_hack_future;
stack_is_running = false;
btif_disable_bluetooth();
module_shut_down(get_module(BTIF_CONFIG_MODULE));
future_await(local_hack_future);
module_shut_down(get_module(CONTROLLER_MODULE)); // Doesn't do any work, just puts it in a restartable state
LOG_INFO(LOG_TAG, "%s finished", __func__);
btif_thread_post(event_signal_stack_down, NULL);
}
static void ensure_stack_is_not_running(void) {
if (stack_is_running) {
LOG_WARN(LOG_TAG, "%s found the stack was still running. Bringing it down now.", __func__);
event_shut_down_stack(NULL);
}
}
// Synchronous function to clean up the stack
static void event_clean_up_stack(void *context) {
if (!stack_is_initialized) {
LOG_INFO(LOG_TAG, "%s found the stack already in a clean state", __func__);
goto cleanup;
}
ensure_stack_is_not_running();
LOG_INFO(LOG_TAG, "%s is cleaning up the stack", __func__);
future_t *local_hack_future = future_new();
hack_future = local_hack_future;
stack_is_initialized = false;
btif_cleanup_bluetooth();
module_clean_up(get_module(BTIF_CONFIG_MODULE));
module_clean_up(get_module(BT_UTILS_MODULE));
module_clean_up(get_module(OSI_MODULE));
module_management_stop();
LOG_INFO(LOG_TAG, "%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();
HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_ON);
}
static void event_signal_stack_down(UNUSED_ATTR void *context) {
HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_OFF);
}
static void ensure_manager_initialized(void) {
if (management_thread)
return;
management_thread = thread_new("stack_manager");
if (!management_thread) {
LOG_ERROR(LOG_TAG, "%s unable to create 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;
}