/******************************************************************************
|
*
|
* 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>
|
|
#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 "osi/include/log.h"
|
#include "osi/include/osi.h"
|
#include "osi/include/semaphore.h"
|
|
// Temp includes
|
#include "bt_utils.h"
|
#include "btif_config.h"
|
#include "btif_profile_queue.h"
|
|
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
|
|
// 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() {
|
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(nullptr);
|
}
|
}
|
|
// 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(nullptr);
|
return;
|
}
|
|
stack_is_running = true;
|
LOG_INFO(LOG_TAG, "%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(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
|
|
hack_future = future_new();
|
do_in_jni_thread(FROM_HERE, base::Bind(event_signal_stack_down, nullptr));
|
future_await(hack_future);
|
LOG_INFO(LOG_TAG, "%s finished", __func__);
|
}
|
|
static void ensure_stack_is_not_running() {
|
if (stack_is_running) {
|
LOG_WARN(LOG_TAG,
|
"%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(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__);
|
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);
|
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(LOG_TAG, "%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; }
|