summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--btcore/Android.mk4
-rw-r--r--btcore/include/module.h55
-rw-r--r--btcore/src/module.c170
-rw-r--r--btif/src/stack_manager.c4
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);
}