diff options
-rw-r--r-- | btcore/Android.mk | 4 | ||||
-rw-r--r-- | btcore/include/module.h | 55 | ||||
-rw-r--r-- | btcore/src/module.c | 170 | ||||
-rw-r--r-- | btif/src/stack_manager.c | 4 |
4 files changed, 232 insertions, 1 deletions
diff --git a/btcore/Android.mk b/btcore/Android.mk index ce00814c1..e362cb32f 100644 --- a/btcore/Android.mk +++ b/btcore/Android.mk @@ -21,10 +21,12 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/include + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/../osi/include LOCAL_SRC_FILES := \ src/bdaddr.c \ + src/module.c \ src/uuid.c LOCAL_CFLAGS := -std=c99 $(bdroid_CFLAGS) diff --git a/btcore/include/module.h b/btcore/include/module.h new file mode 100644 index 000000000..2a0cf09cb --- /dev/null +++ b/btcore/include/module.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * + * 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. + * + ******************************************************************************/ + +#pragma once + +#include <stdbool.h> + +#include "future.h" + +typedef future_t *(*module_lifecycle_fn)(void); + +typedef struct { + char *name; + module_lifecycle_fn init; + module_lifecycle_fn start_up; + module_lifecycle_fn shut_down; + module_lifecycle_fn clean_up; + const char *dependencies[]; +} module_t; + +// Prepares module management. Must be called before doing anything with modules. +void module_management_start(void); +// Cleans up all module management resources. +void module_management_stop(void); + +const module_t *get_module(const char *name); + +// Initialize the provided module. |module| may not be NULL +// and must not be initialized. +bool module_init(const module_t *module); +// Start up the provided module. |module| may not be NULL +// and must be initialized or have no init function. +bool module_start_up(const module_t *module); +// Shut down the provided module. |module| may not be NULL. +// If not started, does nothing. +void module_shut_down(const module_t *module); +// Clean up the provided module. |module| may not be NULL. +// If not initialized, does nothing. +void module_clean_up(const module_t *module); + diff --git a/btcore/src/module.c b/btcore/src/module.c new file mode 100644 index 000000000..1e02f8735 --- /dev/null +++ b/btcore/src/module.c @@ -0,0 +1,170 @@ +/****************************************************************************** + * + * 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_module" + +#include <assert.h> +#include <dlfcn.h> +#include <pthread.h> +#include <utils/Log.h> + +#include "allocator.h" +#include "hash_functions.h" +#include "hash_map.h" +#include "module.h" +#include "osi.h" + +typedef enum { + MODULE_STATE_NONE = 0, + MODULE_STATE_INITIALIZED = 1, + MODULE_STATE_STARTED = 2 +} module_state_t; + +static const size_t number_of_metadata_buckets = 42; +static hash_map_t *metadata; +// Include this lock for now for correctness, while the startup sequence is being refactored +static pthread_mutex_t metadata_lock; + +static bool call_lifecycle_function(module_lifecycle_fn function); +static module_state_t get_module_state(const module_t *module); +static void set_module_state(const module_t *module, module_state_t state); + +void module_management_start(void) { + metadata = hash_map_new( + number_of_metadata_buckets, + hash_function_pointer, + NULL, + osi_free + ); + + pthread_mutex_init(&metadata_lock, NULL); +} + +void module_management_stop(void) { + if (!metadata) + return; + + hash_map_free(metadata); + metadata = NULL; + + pthread_mutex_destroy(&metadata_lock); +} + +const module_t *get_module(const char *name) { + return (module_t *)dlsym(RTLD_DEFAULT, name); +} + +bool module_init(const module_t *module) { + assert(metadata != NULL); + assert(module != NULL); + assert(get_module_state(module) == MODULE_STATE_NONE); + + if (!call_lifecycle_function(module->init)) { + ALOGE("%s failed to initialize \"%s\"", __func__, module->name); + return false; + } + + set_module_state(module, MODULE_STATE_INITIALIZED); + return true; +} + +bool module_start_up(const module_t *module) { + assert(metadata != NULL); + assert(module != NULL); + // TODO(zachoverflow): remove module->init check once automagic order/call is in place. + // This hack is here so modules which don't require init don't have to have useless calls + // as we're converting the startup sequence. + assert(get_module_state(module) == MODULE_STATE_INITIALIZED || module->init == NULL); + + if (!call_lifecycle_function(module->start_up)) { + ALOGE("%s failed to start up \"%s\"", __func__, module->name); + return false; + } + + set_module_state(module, MODULE_STATE_STARTED); + return true; +} + +void module_shut_down(const module_t *module) { + assert(metadata != NULL); + assert(module != NULL); + module_state_t state = get_module_state(module); + assert(state <= MODULE_STATE_STARTED); + + // Only something to do if the module was actually started + if (state < MODULE_STATE_STARTED) + return; + + if (!call_lifecycle_function(module->shut_down)) + ALOGE("%s found \"%s\" reported failure during shutdown. Continuing anyway.", __func__, module->name); + + set_module_state(module, MODULE_STATE_INITIALIZED); +} + +void module_clean_up(const module_t *module) { + assert(metadata != NULL); + assert(module != NULL); + module_state_t state = get_module_state(module); + assert(state <= MODULE_STATE_INITIALIZED); + + // Only something to do if the module was actually initialized + if (state < MODULE_STATE_INITIALIZED) + return; + + if (!call_lifecycle_function(module->clean_up)) + ALOGE("%s found \"%s\" reported failure during cleanup. Continuing anyway.", __func__, module->name); + + set_module_state(module, MODULE_STATE_NONE); +} + +static bool call_lifecycle_function(module_lifecycle_fn function) { + // A NULL lifecycle function means it isn't needed, so assume success + if (!function) + return true; + + future_t *future = function(); + + // A NULL future means synchronous success + if (!future) + return true; + + // Otherwise fall back to the future + return future_await(future); +} + +static module_state_t get_module_state(const module_t *module) { + pthread_mutex_lock(&metadata_lock); + module_state_t *state_ptr = hash_map_get(metadata, module); + pthread_mutex_unlock(&metadata_lock); + + return state_ptr ? *state_ptr : MODULE_STATE_NONE; +} + +static void set_module_state(const module_t *module, module_state_t state) { + pthread_mutex_lock(&metadata_lock); + + module_state_t *state_ptr = hash_map_get(metadata, module); + if (!state_ptr) { + state_ptr = osi_malloc(sizeof(module_state_t)); + hash_map_set(metadata, module, state_ptr); + } + + pthread_mutex_unlock(&metadata_lock); + + *state_ptr = state; +} diff --git a/btif/src/stack_manager.c b/btif/src/stack_manager.c index 0ec816b71..ac4920fab 100644 --- a/btif/src/stack_manager.c +++ b/btif/src/stack_manager.c @@ -24,6 +24,7 @@ #include "btif_api.h" #include "btif_common.h" #include "bt_utils.h" +#include "module.h" #include "osi.h" #include "semaphore.h" #include "stack_manager.h" @@ -85,6 +86,8 @@ static void event_init_stack(void *context) { semaphore_t *semaphore = (semaphore_t *)context; if (!stack_is_initialized) { + module_management_start(); + bt_utils_init(); btif_init_bluetooth(); @@ -143,6 +146,7 @@ static void event_shut_down_stack(UNUSED_ATTR void *context) { btif_disable_bluetooth(); future_await(hack_future); + module_management_stop(); ALOGD("%s finished.", __func__); btif_thread_post(event_signal_stack_down, NULL); } |