gn-build: Add bluetooth-service target
This patch makes the Bluetooth system service (service/) buildable using GN:
1. Added new BUILD.gn file for service/
2. Added conditional compilation for global config paths, with TODOs for
generalizing them later.
3. Added a shim for loading the Bluetooth library that calls hw_get_module on
Android and explicitly calls dlopen on OS_GENERIC.
4. Fixed compile warnings and errors.
5. Did some minor clean up in gatt_server.cpp for better readability.
Bug: 22124644
Change-Id: I3226537a3a5211a6762651a35707638df29956b0
diff --git a/BUILD.gn b/BUILD.gn
index 10cefaa..c9c55eb 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1,4 +1,5 @@
#
+#
# Copyright (C) 2015 Google, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,5 +25,7 @@
group("bluetooth") {
deps = [
"//main:bluetooth.default",
+ "//service:bluetoothtbd",
+ "//vendor_libs:vendor-libs"
]
}
diff --git a/btcore/Android.mk b/btcore/Android.mk
index 50006d4..4863790 100644
--- a/btcore/Android.mk
+++ b/btcore/Android.mk
@@ -32,6 +32,7 @@
src/bdaddr.c \
src/counter.c \
src/device_class.c \
+ src/hal_util.c \
src/module.c \
src/osi_module.c \
src/property.c \
diff --git a/btcore/BUILD.gn b/btcore/BUILD.gn
index 56719ad..624733b 100644
--- a/btcore/BUILD.gn
+++ b/btcore/BUILD.gn
@@ -19,6 +19,7 @@
"src/bdaddr.c",
"src/counter.c",
"src/device_class.c",
+ "src/hal_util.c",
"src/module.c",
"src/property.c",
"src/uuid.c",
diff --git a/btcore/include/hal_util.h b/btcore/include/hal_util.h
new file mode 100644
index 0000000..8456a71
--- /dev/null
+++ b/btcore/include/hal_util.h
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2015 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
+
+struct hw_module_t;
+
+// Loads the Bluetooth library. If OS_GENERIC is defined, this function looks
+// explicitly for libbluetooth.default.so and loads it. On Android, this calls
+// the hw_get_module routine with the Bluetooth stack module id.
+int hal_util_load_bt_library(const struct hw_module_t **module);
diff --git a/btcore/src/hal_util.c b/btcore/src/hal_util.c
new file mode 100644
index 0000000..c2bf880
--- /dev/null
+++ b/btcore/src/hal_util.c
@@ -0,0 +1,92 @@
+//
+// Copyright (C) 2015 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 "hal_util"
+
+#include <hardware/bluetooth.h>
+#include <hardware/hardware.h>
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+#include "btcore/include/hal_util.h"
+#include "osi/include/log.h"
+
+#if defined(OS_GENERIC)
+
+// TODO(armansito): All logging macros should include __func__ by default (see
+// Bug: 22671731)
+#define HULOGERR(fmt, args...) \
+ LOG_ERROR(LOG_TAG, "[%s] failed to load the Bluetooth library: " fmt, \
+ __func__, ## args)
+
+// TODO(armansito): It might be better to pass the library name in a more
+// generic manner as opposed to hard-coding it here.
+static const char kBluetoothLibraryName[] = "libbluetooth.default.so";
+
+static int load_bt_library(const struct hw_module_t **module) {
+ const char *id = BT_STACK_MODULE_ID;
+
+ // Always try to load the default Bluetooth stack on GN builds.
+ void *handle = dlopen(kBluetoothLibraryName, RTLD_NOW);
+ if (!handle) {
+ char const *err_str = dlerror();
+ HULOGERR("%s", err_str ? err_str : "error unknown");
+ goto error;
+ }
+
+ // Get the address of the struct hal_module_info.
+ const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
+ struct hw_module_t *hmi = (struct hw_module_t *)dlsym(handle, sym);
+ if (!hmi) {
+ HULOGERR("%s", sym);
+ goto error;
+ }
+
+ // Check that the id matches.
+ if (strcmp(id, hmi->id) != 0) {
+ HULOGERR("id=%s does not match HAL module ID: %s", id, hmi->id);
+ goto error;
+ }
+
+ hmi->dso = handle;
+
+ // Success.
+ LOG_INFO(
+ LOG_TAG, "[%s] loaded HAL id=%s path=%s hmi=%p handle=%p",
+ __func__, id, kBluetoothLibraryName, hmi, handle);
+
+ *module = hmi;
+ return 0;
+
+error:
+ *module = NULL;
+ if (handle)
+ dlclose(handle);
+
+ return -EINVAL;
+}
+
+#endif // defined(OS_GENERIC)
+
+int hal_util_load_bt_library(const struct hw_module_t **module) {
+#if defined(OS_GENERIC)
+ return load_bt_library(module);
+#else // !defined(OS_GENERIC)
+ return hw_get_module(BT_STACK_MODULE_ID, module);
+#endif // defined(OS_GENERIC)
+}
diff --git a/btif/src/btif_config.c b/btif/src/btif_config.c
index d926f8a..0dc95b8 100644
--- a/btif/src/btif_config.c
+++ b/btif/src/btif_config.c
@@ -38,7 +38,12 @@
#include "osi/include/log.h"
#include "osi/include/osi.h"
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+static const char *CONFIG_FILE_PATH = "bt_config.conf";
+#else // !defined(OS_GENERIC)
static const char *CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
+#endif // defined(OS_GENERIC)
static const char *LEGACY_CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.xml";
static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000;
diff --git a/btif/src/btif_core.c b/btif/src/btif_core.c
index 7ff8163..23b51dd 100644
--- a/btif/src/btif_core.c
+++ b/btif/src/btif_core.c
@@ -75,8 +75,13 @@
************************************************************************************/
#ifndef BTE_DID_CONF_FILE
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+#define BTE_DID_CONF_FILE "bt_did.conf"
+#else // !defined(OS_GENERIC)
#define BTE_DID_CONF_FILE "/etc/bluetooth/bt_did.conf"
-#endif
+#endif // defined(OS_GENERIC)
+#endif // BTE_DID_CONF_FILE
/************************************************************************************
** Local type definitions
diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
index 079ecf0..9e99901 100644
--- a/btif/src/btif_storage.c
+++ b/btif/src/btif_storage.c
@@ -57,6 +57,7 @@
** Constants & Macros
************************************************************************************/
+// TODO(armansito): Find a better way than using a hardcoded path.
#define BTIF_STORAGE_PATH_BLUEDROID "/data/misc/bluedroid"
//#define BTIF_STORAGE_PATH_ADAPTER_INFO "adapter_info"
@@ -78,7 +79,12 @@
#define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "DiscoveryTimeout"
-#define BTIF_AUTO_PAIR_CONF_FILE "/etc/bluetooth/auto_pair_devlist.conf"
+#if defined(OS_GENERIC)
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#define BTIF_AUTO_PAIR_CONF_FILE "auto_pair_devlist.conf"
+#else // !defined(OS_GENERIC)
+#define BTIF_AUTO_PAIR_CONF_FILE "/etc/bluetooth/auto_pair_devlist.conf"
+#endif // defined(OS_GENERIC)
#define BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST "AutoPairBlacklist"
#define BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_ADDR "AddressBlacklist"
#define BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_EXACTNAME "ExactNameBlacklist"
diff --git a/build/secondary/third_party/libchrome/BUILD.gn b/build/secondary/third_party/libchrome/BUILD.gn
index 62884b8..4d1b6bd 100644
--- a/build/secondary/third_party/libchrome/BUILD.gn
+++ b/build/secondary/third_party/libchrome/BUILD.gn
@@ -224,5 +224,5 @@
"-Wno-sign-promo",
]
- libs = [ "-levent", "-levent_core" ]
+ libs = [ "-levent", "-levent_core", "-lpthread" ]
}
diff --git a/main/BUILD.gn b/main/BUILD.gn
index a80e31d..37cafbe 100644
--- a/main/BUILD.gn
+++ b/main/BUILD.gn
@@ -74,5 +74,5 @@
"//utils",
]
- libs = [ "-lpthread", "-lrt", "-ldl" ]
+ libs = [ "-ldl", "-lpthread", "-lresolv", "-lrt", "-lz" ]
}
diff --git a/main/bte_main.c b/main/bte_main.c
index f165f52..ba8b172 100644
--- a/main/bte_main.c
+++ b/main/bte_main.c
@@ -62,8 +62,13 @@
/* Run-time configuration file for BLE*/
#ifndef BTE_BLE_STACK_CONF_FILE
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+#define BTE_BLE_STACK_CONF_FILE "ble_stack.conf"
+#else // !defined(OS_GENERIC)
#define BTE_BLE_STACK_CONF_FILE "/etc/bluetooth/ble_stack.conf"
-#endif
+#endif // defined(OS_GENERIC)
+#endif // BT_BLE_STACK_CONF_FILE
/******************************************************************************
** Variables
diff --git a/main/stack_config.c b/main/stack_config.c
index 53dda72..cbc1c71 100644
--- a/main/stack_config.c
+++ b/main/stack_config.c
@@ -35,7 +35,12 @@
// Module lifecycle functions
static future_t *init() {
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+ const char *path = "bt_stack.conf";
+#else // !defined(OS_GENERIC)
const char *path = "/etc/bluetooth/bt_stack.conf";
+#endif // defined(OS_GENERIC)
assert(path != NULL);
LOG_INFO(LOG_TAG, "%s attempt to load stack conf from %s", __func__, path);
diff --git a/osi/BUILD.gn b/osi/BUILD.gn
index 3284aaf..5139dc0 100644
--- a/osi/BUILD.gn
+++ b/osi/BUILD.gn
@@ -32,6 +32,7 @@
"src/list.c",
"src/non_repeating_timer.c",
"src/reactor.c",
+ "src/ringbuffer.c",
"src/semaphore.c",
"src/socket.c",
@@ -65,6 +66,7 @@
"test/hash_map_test.cpp",
"test/list_test.cpp",
"test/reactor_test.cpp",
+ "test/ringbuffer_test.cpp",
"test/thread_test.cpp",
]
diff --git a/service/Android.mk b/service/Android.mk
index a946d51..64856d1 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -39,8 +39,9 @@
LOCAL_CFLAGS += -std=c++11
LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := bthost
+LOCAL_MODULE := bluetoothtbd
LOCAL_REQUIRED_MODULES = bluetooth.default
+LOCAL_STATIC_LIBRARIES += libbtcore
LOCAL_SHARED_LIBRARIES += \
libchrome \
libcutils \
diff --git a/service/BUILD.gn b/service/BUILD.gn
new file mode 100644
index 0000000..4beeaed
--- /dev/null
+++ b/service/BUILD.gn
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2015 Google
+#
+# 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.
+#
+
+executable("bluetoothtbd") {
+ sources = [
+ "a2dp_source.cpp",
+ "core_stack.cpp",
+ "gatt_server.cpp",
+ "host.cpp",
+ "logging_helpers.cpp",
+ "main.cpp",
+ "uuid.cpp"
+ ]
+
+ include_dirs = [
+ "//",
+ "//third_party/libchrome"
+ ]
+
+ deps = [
+ "//btcore",
+ "//third_party/libchrome:base",
+ "//third_party/modp_b64",
+ ]
+
+ libs = [ "-ldl", "-lpthread", "-lrt" ]
+}
diff --git a/service/a2dp_source.cpp b/service/a2dp_source.cpp
index ea01188..1b21cc1 100644
--- a/service/a2dp_source.cpp
+++ b/service/a2dp_source.cpp
@@ -26,12 +26,12 @@
void ConnectionStateCallback(btav_connection_state_t state,
UNUSED_ATTR bt_bdaddr_t *bd_addr) {
- LOG_INFO("%s: %s", __func__, BtAvConnectionStateText(state));
+ LOG_INFO(LOG_TAG, "%s: %s", __func__, BtAvConnectionStateText(state));
}
void AudioStateCallback(btav_audio_state_t state,
UNUSED_ATTR bt_bdaddr_t *bd_addr) {
- LOG_INFO("%s: %s", __func__, BtAvAudioStateText(state));
+ LOG_INFO(LOG_TAG, "%s: %s", __func__, BtAvAudioStateText(state));
}
void AudioConfigCallback(UNUSED_ATTR bt_bdaddr_t *bd_addr,
diff --git a/service/core_stack.cpp b/service/core_stack.cpp
index 5e63c36..f5f94f3 100644
--- a/service/core_stack.cpp
+++ b/service/core_stack.cpp
@@ -18,18 +18,25 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <time.h>
#include <condition_variable>
#include <mutex>
#include <string>
-#define LOG_TAG "bt_bluetooth_base"
-#include "osi/include/log.h"
+#include <hardware/bluetooth.h>
+#include <hardware/hardware.h>
-#include "hardware/bluetooth.h"
-#include "hardware/hardware.h"
+// TODO(armansito): Remove this line and use base/logging.h instead.
+#define LOG_TAG "bluetooth_daemon"
+
#include "logging_helpers.h"
+
+extern "C" {
+#include "btcore/include/hal_util.h"
+#include "osi/include/log.h"
#include "osi/include/osi.h"
+} // extern "C"
namespace {
@@ -185,7 +192,7 @@
// Load the bluetooth module.
const hw_module_t *module;
- int status = hw_get_module(BT_HARDWARE_MODULE_ID, &module);
+ int status = hal_util_load_bt_library(&module);
if (status) {
LOG_ERROR(LOG_TAG, "Error getting bluetooth module");
return false;
diff --git a/service/gatt_server.cpp b/service/gatt_server.cpp
index 03aa545..f2f56e2 100644
--- a/service/gatt_server.cpp
+++ b/service/gatt_server.cpp
@@ -47,7 +47,27 @@
const int kNumBlueDroidHandles = 60;
// TODO(icoolidge): Support multiple instances
-static bluetooth::gatt::ServerInternals *internal = nullptr;
+// TODO(armansito): Remove this variable. No point of having this if
+// each bluetooth::gatt::Server instance already keeps a pointer to the
+// ServerInternals that is associated with it (which is much cleaner). It looks
+// like this variable exists because the btif callbacks don't allow the
+// upper-layer to pass user data to them. We could:
+//
+// 1. Fix the btif callbacks so that some sort of continuation can be
+// attached to a callback. This might be a long shot since the callback
+// interface doesn't allow more than one caller to register its own callbacks
+// (which might be what we want though, since this would make the API more
+// flexible).
+//
+// 2. Allow creation of Server objects using a factory method that returns
+// the result asynchronously in a base::Callback. The RegisterServerCallback
+// provides an |app_uuid|, which can be used to store callback structures in
+// a map and lazily instantiate the Server and invoke the correct callback.
+// This is a general pattern that we should use throughout the daemon, since
+// all operations can timeout or fail and this is best reported in an
+// asynchronous base::Callback.
+//
+static bluetooth::gatt::ServerInternals *g_internal = nullptr;
enum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 };
@@ -71,6 +91,10 @@
ServerInternals();
~ServerInternals();
int Initialize(CoreStack *bt);
+ bt_status_t AddCharacteristic(
+ const Uuid& uuid,
+ int properties,
+ int permissions);
// This maps API attribute UUIDs to BlueDroid handles.
std::map<Uuid, int> uuid_to_attribute;
@@ -106,14 +130,14 @@
LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d app_uuid:%p", __func__, status,
server_if, app_uuid);
- internal->server_if = server_if;
+ g_internal->server_if = server_if;
btgatt_srvc_id_t service_id;
service_id.id.uuid = *app_uuid;
service_id.id.inst_id = 0;
service_id.is_primary = true;
- bt_status_t btstat = internal->gatt->server->add_service(
+ g_internal->gatt->server->add_service(
server_if, &service_id, kNumBlueDroidHandles);
}
@@ -122,20 +146,20 @@
LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d gatt_srvc_id:%u srvc_handle:%d",
__func__, status, server_if, srvc_id->id.inst_id, srvc_handle);
- std::lock_guard<std::mutex> lock(internal->lock);
- internal->server_if = server_if;
- internal->service_handle = srvc_handle;
- internal->service_id = *srvc_id;
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+ g_internal->server_if = server_if;
+ g_internal->service_handle = srvc_handle;
+ g_internal->service_id = *srvc_id;
// This finishes the Initialize call.
- internal->api_synchronize.notify_one();
+ g_internal->api_synchronize.notify_one();
}
void RequestReadCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
int attr_handle, int attribute_offset_octets,
bool is_long) {
- std::lock_guard<std::mutex> lock(internal->lock);
+ std::lock_guard<std::mutex> lock(g_internal->lock);
- bluetooth::gatt::Characteristic &ch = internal->characteristics[attr_handle];
+ bluetooth::gatt::Characteristic &ch = g_internal->characteristics[attr_handle];
// Latch next_blob to blob on a 'fresh' read.
if (ch.next_blob_pending && attribute_offset_octets == 0 &&
@@ -169,7 +193,7 @@
response.attr_value.handle = attr_handle;
response.attr_value.offset = attribute_offset_octets;
response.attr_value.auth_req = 0;
- internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+ g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
}
void RequestWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
@@ -183,32 +207,34 @@
__func__, conn_id, addr.c_str(), trans_id, attr_handle, attribute_offset,
length, need_rsp, is_prep);
- std::lock_guard<std::mutex> lock(internal->lock);
+ std::lock_guard<std::mutex> lock(g_internal->lock);
- bluetooth::gatt::Characteristic &ch = internal->characteristics[attr_handle];
+ bluetooth::gatt::Characteristic &ch =
+ g_internal->characteristics[attr_handle];
ch.blob.resize(attribute_offset + length);
std::copy(value, value + length, ch.blob.begin() + attribute_offset);
- auto target_blob = internal->controlled_blobs.find(attr_handle);
+ auto target_blob = g_internal->controlled_blobs.find(attr_handle);
// If this is a control attribute, adjust offset of the target blob.
- if (target_blob != internal->controlled_blobs.end() && ch.blob.size() == 1u) {
- internal->characteristics[target_blob->second].blob_section = ch.blob[0];
+ if (target_blob != g_internal->controlled_blobs.end() &&
+ ch.blob.size() == 1u) {
+ g_internal->characteristics[target_blob->second].blob_section = ch.blob[0];
LOG_INFO(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__,
target_blob->second, ch.blob[0]);
} else if (!is_prep) {
// This is a single frame characteristic write.
// Notify upwards because we're done now.
const bluetooth::Uuid::Uuid128Bit &attr_uuid = ch.uuid.GetFullBigEndian();
- int status = write(internal->pipefd[kPipeWriteEnd], attr_uuid.data(),
+ int status = write(g_internal->pipefd[kPipeWriteEnd], attr_uuid.data(),
attr_uuid.size());
if (-1 == status)
LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
} else {
// This is a multi-frame characteristic write.
// Wait for an 'RequestExecWriteCallback' to notify completion.
- internal->last_write = ch.uuid;
+ g_internal->last_write = ch.uuid;
}
// Respond only if needed.
@@ -222,7 +248,7 @@
// Provide written data back to sender for the response.
// Remote stacks use this to validate the success of the write.
std::copy(value, value + length, response.attr_value.value);
- internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+ g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
}
void RequestExecWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
@@ -234,16 +260,17 @@
// This 'response' data is unused for ExecWriteResponses.
// It is only used to pass BlueDroid argument validation.
btgatt_response_t response = {};
- internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+ g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
if (!exec_write)
return;
- std::lock_guard<std::mutex> lock(internal->lock);
+ std::lock_guard<std::mutex> lock(g_internal->lock);
// Communicate the attribute UUID as notification of a write update.
const bluetooth::Uuid::Uuid128Bit uuid =
- internal->last_write.GetFullBigEndian();
- int status = write(internal->pipefd[kPipeWriteEnd], uuid.data(), uuid.size());
+ g_internal->last_write.GetFullBigEndian();
+ int status = write(g_internal->pipefd[kPipeWriteEnd],
+ uuid.data(), uuid.size());
if (-1 == status)
LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
}
@@ -254,28 +281,28 @@
LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s",
__func__, conn_id, server_if, connected, addr.c_str());
if (connected == 1) {
- internal->connections.insert(conn_id);
+ g_internal->connections.insert(conn_id);
} else if (connected == 0) {
- internal->connections.erase(conn_id);
+ g_internal->connections.erase(conn_id);
}
}
void CharacteristicAddedCallback(int status, int server_if, bt_uuid_t *uuid,
int srvc_handle, int char_handle) {
LOG_INFO(LOG_TAG,
- "%s: status:%d server_if:%d service_handle:%d char_handle:%d", __func__,
+ "%s: status:%d server_if:%d service_handle:%d char_handle:%d", __func__,
status, server_if, srvc_handle, char_handle);
bluetooth::Uuid id(*uuid);
- std::lock_guard<std::mutex> lock(internal->lock);
+ std::lock_guard<std::mutex> lock(g_internal->lock);
- internal->uuid_to_attribute[id] = char_handle;
- internal->characteristics[char_handle].uuid = id;
- internal->characteristics[char_handle].blob_section = 0;
+ g_internal->uuid_to_attribute[id] = char_handle;
+ g_internal->characteristics[char_handle].uuid = id;
+ g_internal->characteristics[char_handle].blob_section = 0;
// This terminates an AddCharacteristic.
- internal->api_synchronize.notify_one();
+ g_internal->api_synchronize.notify_one();
}
void DescriptorAddedCallback(int status, int server_if, bt_uuid_t *uuid,
@@ -293,10 +320,10 @@
// The UUID provided here is unimportant, and is only used to satisfy
// BlueDroid.
// It must be different than any other registered UUID.
- bt_uuid_t client_id = internal->service_id.id.uuid;
+ bt_uuid_t client_id = g_internal->service_id.id.uuid;
++client_id.uu[15];
- bt_status_t btstat = internal->gatt->client->register_client(&client_id);
+ bt_status_t btstat = g_internal->gatt->client->register_client(&client_id);
if (btstat != BT_STATUS_SUCCESS) {
LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__);
}
@@ -305,10 +332,10 @@
void RegisterClientCallback(int status, int client_if, bt_uuid_t *app_uuid) {
LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%u", __func__, status,
client_if, app_uuid->uu[0]);
- internal->client_if = client_if;
+ g_internal->client_if = client_if;
// Setup our advertisement. This has no callback.
- bt_status_t btstat = internal->gatt->client->set_adv_data(
+ bt_status_t btstat = g_internal->gatt->client->set_adv_data(
client_if, false, /* beacon, not scan response */
false, /* name */
false, /* no txpower */
@@ -324,7 +351,7 @@
// TODO(icoolidge): Deprecated, use multi-adv interface.
// This calls back to ListenCallback.
- btstat = internal->gatt->client->listen(client_if, true);
+ btstat = g_internal->gatt->client->listen(client_if, true);
if (btstat != BT_STATUS_SUCCESS) {
LOG_ERROR(LOG_TAG, "Failed to start listening");
}
@@ -333,30 +360,30 @@
void ListenCallback(int status, int client_if) {
LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d", __func__, status, client_if);
// This terminates a Start call.
- std::lock_guard<std::mutex> lock(internal->lock);
- internal->api_synchronize.notify_one();
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+ g_internal->api_synchronize.notify_one();
}
void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
- LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
+ LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
status, server_if, srvc_handle);
// This terminates a Stop call.
// TODO(icoolidge): make this symmetric with start
- std::lock_guard<std::mutex> lock(internal->lock);
- internal->api_synchronize.notify_one();
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+ g_internal->api_synchronize.notify_one();
}
void ScanResultCallback(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data) {
std::string addr(BtAddrString(bda));
(void)adv_data;
- std::lock_guard<std::mutex> lock(internal->lock);
- internal->scan_results[addr] = rssi;
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+ g_internal->scan_results[addr] = rssi;
}
void ClientConnectCallback(int conn_id, int status, int client_if,
bt_bdaddr_t *bda) {
std::string addr(BtAddrString(bda));
- LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
+ LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
conn_id, status, client_if, addr.c_str());
}
@@ -472,6 +499,15 @@
return 0;
}
+bt_status_t ServerInternals::AddCharacteristic(
+ const Uuid& uuid,
+ int properties,
+ int permissions) {
+ bt_uuid_t c_uuid = uuid.GetBlueDroid();
+ return gatt->server->add_characteristic(
+ server_if, service_handle, &c_uuid, properties, permissions);
+}
+
ServerInternals::ServerInternals()
: gatt(nullptr),
server_if(0),
@@ -500,7 +536,7 @@
LOG_ERROR(LOG_TAG, "Error creating internals");
return false;
}
- internal = internal_.get();
+ g_internal = internal_.get();
std::unique_lock<std::mutex> lock(internal_->lock);
int status = internal_->Initialize(bt);
@@ -543,7 +579,7 @@
std::lock_guard<std::mutex> lock(internal_->lock);
// Setup our advertisement. This has no callback.
- bt_status_t btstat = internal->gatt->client->set_adv_data(
+ bt_status_t btstat = internal_->gatt->client->set_adv_data(
internal_->client_if, false, /* beacon, not scan response */
transmit_name, /* name */
false, /* no txpower */
@@ -574,7 +610,7 @@
std::lock_guard<std::mutex> lock(internal_->lock);
// Setup our advertisement. This has no callback.
- bt_status_t btstat = internal->gatt->client->set_adv_data(
+ bt_status_t btstat = internal_->gatt->client->set_adv_data(
internal_->client_if, true, /* scan response */
transmit_name, /* name */
false, /* no txpower */
@@ -591,50 +627,53 @@
return true;
}
-bool Server::AddCharacteristic(const Uuid &id, int properties, int permissions) {
- bt_uuid_t char_id = id.GetBlueDroid();
-
- std::unique_lock<std::mutex> lock(internal->lock);
- bt_status_t btstat = internal->gatt->server->add_characteristic(
- internal->server_if, internal->service_handle, &char_id, properties,
- permissions);
+bool Server::AddCharacteristic(
+ const Uuid &id, int properties, int permissions) {
+ std::unique_lock<std::mutex> lock(internal_->lock);
+ bt_status_t btstat = internal_->AddCharacteristic(
+ id, properties, permissions);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x",
+ internal_->service_handle);
+ return false;
+ }
internal_->api_synchronize.wait(lock);
- const int handle = internal->uuid_to_attribute[id];
- internal->characteristics[handle].notify = properties & kPropertyNotify;
+ const int handle = internal_->uuid_to_attribute[id];
+ internal_->characteristics[handle].notify = properties & kPropertyNotify;
return true;
}
bool Server::AddBlob(const Uuid &id, const Uuid &control_id, int properties,
int permissions) {
- bt_uuid_t char_id = id.GetBlueDroid();
- bt_uuid_t ctrl_id = control_id.GetBlueDroid();
-
- std::unique_lock<std::mutex> lock(internal->lock);
+ std::unique_lock<std::mutex> lock(internal_->lock);
// First, add the primary attribute (characteristic value)
- bt_status_t btstat = internal->gatt->server->add_characteristic(
- internal->server_if, internal->service_handle, &char_id, properties,
- permissions);
- internal->api_synchronize.wait(lock);
+ bt_status_t btstat = internal_->AddCharacteristic(
+ id, properties, permissions);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to set scan response data");
+ return false;
+ }
+
+ internal_->api_synchronize.wait(lock);
// Next, add the secondary attribute (blob control).
// Control attributes have fixed permissions/properties.
- const int kControlPermissions = kPermissionRead | kPermissionWrite;
- const int kControlProperties = kPropertyRead | kPropertyWrite;
-
- btstat = internal->gatt->server->add_characteristic(
- internal->server_if, internal->service_handle, &ctrl_id,
- kControlProperties, kControlPermissions);
- internal->api_synchronize.wait(lock);
+ btstat = internal_->AddCharacteristic(
+ control_id,
+ kPermissionRead | kPermissionWrite,
+ kPropertyRead | kPropertyWrite);
+ internal_->api_synchronize.wait(lock);
// Finally, associate the control attribute with the value attribute.
// Also, initialize the control attribute to a readable zero.
- const int control_attribute = internal->uuid_to_attribute[control_id];
- const int blob_attribute = internal->uuid_to_attribute[id];
- internal->controlled_blobs[control_attribute] = blob_attribute;
- internal->characteristics[blob_attribute].notify = properties & kPropertyNotify;
+ const int control_attribute = internal_->uuid_to_attribute[control_id];
+ const int blob_attribute = internal_->uuid_to_attribute[id];
+ internal_->controlled_blobs[control_attribute] = blob_attribute;
+ internal_->characteristics[blob_attribute].notify =
+ properties & kPropertyNotify;
- Characteristic &ctrl = internal->characteristics[control_attribute];
+ Characteristic &ctrl = internal_->characteristics[control_attribute];
ctrl.next_blob.clear();
ctrl.next_blob.push_back(0);
ctrl.next_blob_pending = true;
@@ -647,6 +686,11 @@
std::unique_lock<std::mutex> lock(internal_->lock);
bt_status_t btstat = internal_->gatt->server->start_service(
internal_->server_if, internal_->service_handle, GATT_TRANSPORT_LE);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x",
+ internal_->service_handle);
+ return false;
+ }
internal_->api_synchronize.wait(lock);
return true;
}
@@ -655,6 +699,11 @@
std::unique_lock<std::mutex> lock(internal_->lock);
bt_status_t btstat = internal_->gatt->server->stop_service(
internal_->server_if, internal_->service_handle);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x",
+ internal_->service_handle);
+ return false;
+ }
internal_->api_synchronize.wait(lock);
return true;
}
@@ -685,18 +734,18 @@
bool Server::SetCharacteristicValue(const Uuid &id,
const std::vector<uint8_t> &value) {
- std::lock_guard<std::mutex> lock(internal->lock);
- const int attribute_id = internal->uuid_to_attribute[id];
- Characteristic &ch = internal->characteristics[attribute_id];
+ std::lock_guard<std::mutex> lock(internal_->lock);
+ const int attribute_id = internal_->uuid_to_attribute[id];
+ Characteristic &ch = internal_->characteristics[attribute_id];
ch.next_blob = value;
ch.next_blob_pending = true;
if (!ch.notify)
return true;
- for (auto connection : internal->connections) {
+ for (auto connection : internal_->connections) {
char dummy = 0;
- internal_->gatt->server->send_indication(internal->server_if,
+ internal_->gatt->server->send_indication(internal_->server_if,
attribute_id,
connection,
sizeof(dummy),
diff --git a/service/gatt_server.h b/service/gatt_server.h
index 2328395..c61399a 100644
--- a/service/gatt_server.h
+++ b/service/gatt_server.h
@@ -53,7 +53,10 @@
// A mapping from string bluetooth addresses to RSSI measurements.
typedef std::unordered_map<std::string, int> ScanResults;
-class ServerInternals;
+// TODO(armansito): This should be a private internal class though I don't see
+// why we even need this class. Instead it should probably be merged into
+// Server.
+struct ServerInternals;
// Server is threadsafe and internally locked.
// Asynchronous IO is identified via a gatt_pipe FD,
diff --git a/service/host.cpp b/service/host.cpp
index a6bc375..af3c2c5 100644
--- a/service/host.cpp
+++ b/service/host.cpp
@@ -26,12 +26,12 @@
#include <algorithm>
+#include <base/base64.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
+
#define LOG_TAG "bt_bluetooth_host"
#include "osi/include/log.h"
-
-#include "base/base64.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
#include "core_stack.h"
#include "gatt_server.h"
#include "uuid.h"
@@ -178,7 +178,7 @@
const std::string& advertise_uuids,
const std::string& advertise_data,
const std::string& transmit_name) {
- LOG_INFO("%s: service:%s uuids:%s data:%s", __func__, service_uuid.c_str(),
+ LOG_INFO(LOG_TAG, "%s: service:%s uuids:%s data:%s", __func__, service_uuid.c_str(),
advertise_uuids.c_str(), advertise_data.c_str());
std::vector<std::string> advertise_uuid_tokens;
@@ -232,7 +232,7 @@
LOG_ERROR(LOG_TAG, "Error reading datagram size: %s", strerror(errno));
return false;
} else if (0 == size) {
- LOG_INFO("%s:%d: Connection closed", __func__, __LINE__);
+ LOG_INFO(LOG_TAG, "%s:%d: Connection closed", __func__, __LINE__);
return false;
}
@@ -242,7 +242,7 @@
LOG_ERROR(LOG_TAG, "Error reading IPC: %s", strerror(errno));
return false;
} else if (0 == size) {
- LOG_INFO("%s:%d: Connection closed", __func__, __LINE__);
+ LOG_INFO(LOG_TAG, "%s:%d: Connection closed", __func__, __LINE__);
return false;
}
diff --git a/service/main.cpp b/service/main.cpp
index cb536eb..46bff4a 100644
--- a/service/main.cpp
+++ b/service/main.cpp
@@ -13,14 +13,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
+
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
#define LOG_TAG "bt_host"
// For system properties
// TODO(icoolidge): abstraction or non-cutils stub.
+#if !defined(OS_GENERIC)
#include <cutils/properties.h>
+#endif // !defined(OS_GENERIC)
#include "core_stack.h"
#include "host.h"
@@ -29,27 +35,62 @@
namespace {
+// TODO(armansito): None of these should be hardcoded here. Instead, pass these
+// via commandline.
const char kDisableProperty[] = "persist.bluetooth.disable";
const char kSocketFromInit[] = "bluetooth";
+const char kUnixIpcSocketPath[] = "bluetooth-ipc-socket";
} // namespace
int main() {
+ // TODO(armansito): Move all of the IPC connection establishment into its own
+ // class. Here we should only need to initialize and start the main
+ // MessageLoop and the CoreStack instance.
+ int status;
+
+#if !defined(OS_GENERIC)
char disable_value[PROPERTY_VALUE_MAX];
- int status = property_get(kDisableProperty, disable_value, nullptr);
+ status = property_get(kDisableProperty, disable_value, nullptr);
if (status && !strcmp(disable_value, "1")) {
LOG_INFO(LOG_TAG, "%s", "service disabled");
return EXIT_SUCCESS;
}
int server_socket = osi_android_get_control_socket(kSocketFromInit);
- if (server_socket == -1) {
+ if (server_socket < 0) {
LOG_ERROR(LOG_TAG, "failed to get socket from init");
return EXIT_FAILURE;
}
+#else // defined(OS_GENERIC)
+ int server_socket = socket(PF_UNIX, SOCK_SEQPACKET, 0);
+ if (server_socket < 0) {
+ LOG_ERROR(LOG_TAG, "failed to open domain socket for IPC");
+ return EXIT_FAILURE;
+ }
+
+ // TODO(armansito): This is opens the door to potentially unlinking files in
+ // the current directory that we're not supposed to. For now we will have an
+ // assumption that the daemon runs in a sandbox but we should generally do
+ // this properly.
+ //
+ // Also, the daemon should clean this up properly as it shuts down.
+ unlink(kUnixIpcSocketPath);
+
+ struct sockaddr_un address;
+ memset(&address, 0, sizeof(address));
+ address.sun_family = AF_UNIX;
+ strncpy(address.sun_path, kUnixIpcSocketPath, sizeof(address.sun_path) - 1);
+
+ if (bind(server_socket, (struct sockaddr*)&address, sizeof(address)) < 0) {
+ LOG_ERROR(LOG_TAG, "Failed to bind IPC socket to address");
+ return EXIT_FAILURE;
+ }
+
+#endif // !defined(OS_GENERIC)
status = listen(server_socket, SOMAXCONN);
- if (status == -1) {
+ if (status < 0) {
LOG_ERROR(LOG_TAG, "listen failed: %s", strerror(errno));
return EXIT_FAILURE;
}
@@ -71,5 +112,6 @@
}
close(server_socket);
+
return EXIT_SUCCESS;
}
diff --git a/service/uuid.cpp b/service/uuid.cpp
index 13e21a1..c48ba5e 100644
--- a/service/uuid.cpp
+++ b/service/uuid.cpp
@@ -24,8 +24,8 @@
void Uuid::InitializeDefault() {
// Initialize to base bluetooth UUID.
- id_ = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
- 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+ id_ = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}};
}
Uuid::Uuid() {