diff --git a/BUILD.gn b/BUILD.gn index 10cefaac38b499ff057462f454a4d0db232e9277..c9c55eb5f3cc9db1f2bf67f8e06be6bdf761dff2 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/system/btcore/Android.mk b/system/btcore/Android.mk index 50006d4e11e616447f10248c8932c87b4662488f..4863790e64cd3f4c8daf56717b6b0cd3b3f25a7e 100644 --- a/system/btcore/Android.mk +++ b/system/btcore/Android.mk @@ -32,6 +32,7 @@ LOCAL_SRC_FILES := \ 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/system/btcore/BUILD.gn b/system/btcore/BUILD.gn index 56719ad71ffa522732c9fe32b2a58fa27564ffde..624733bca721d7726b7ff36761ae14e5371ad5d0 100644 --- a/system/btcore/BUILD.gn +++ b/system/btcore/BUILD.gn @@ -19,6 +19,7 @@ static_library("btcore") { "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/system/btcore/include/hal_util.h b/system/btcore/include/hal_util.h new file mode 100644 index 0000000000000000000000000000000000000000..8456a7179a5f2767f13ed1b6bc953f9ec725c839 --- /dev/null +++ b/system/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/system/btcore/src/hal_util.c b/system/btcore/src/hal_util.c new file mode 100644 index 0000000000000000000000000000000000000000..c2bf88099b6b19b7af226591e446d61cccdc8d2f --- /dev/null +++ b/system/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/system/btif/src/btif_config.c b/system/btif/src/btif_config.c index d926f8a84765972125eb6aa45d925429718ef22d..0dc95b8b61692042bdb113bcb1dba56b4d7bac35 100644 --- a/system/btif/src/btif_config.c +++ b/system/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/system/btif/src/btif_core.c b/system/btif/src/btif_core.c index 7ff816376b94727aa86d1b9d73010992974ab169..23b51dd9f6a75d14ab1b1001b889895ba33611a8 100644 --- a/system/btif/src/btif_core.c +++ b/system/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/system/btif/src/btif_storage.c b/system/btif/src/btif_storage.c index 079ecf02d0aba3da594884430c744db48bd3d918..9e99901f9ebe60753c0b056d709ce80a37ae73a9 100644 --- a/system/btif/src/btif_storage.c +++ b/system/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/system/build/secondary/third_party/libchrome/BUILD.gn b/system/build/secondary/third_party/libchrome/BUILD.gn index 62884b8335577c1c3ffade6d8881cfbcd17b02de..4d1b6bd1094afae4c3b12d0ae069874b9c211080 100644 --- a/system/build/secondary/third_party/libchrome/BUILD.gn +++ b/system/build/secondary/third_party/libchrome/BUILD.gn @@ -224,5 +224,5 @@ static_library("base") { "-Wno-sign-promo", ] - libs = [ "-levent", "-levent_core" ] + libs = [ "-levent", "-levent_core", "-lpthread" ] } diff --git a/system/main/BUILD.gn b/system/main/BUILD.gn index a80e31df72ebfb026c4c5f323dd6d5f63fbf5d3c..37cafbe82348d713a2444ec64d0a61e1afc6805a 100644 --- a/system/main/BUILD.gn +++ b/system/main/BUILD.gn @@ -74,5 +74,5 @@ shared_library("bluetooth.default") { "//utils", ] - libs = [ "-lpthread", "-lrt", "-ldl" ] + libs = [ "-ldl", "-lpthread", "-lresolv", "-lrt", "-lz" ] } diff --git a/system/main/bte_main.c b/system/main/bte_main.c index f165f520a05ad3a3523c29b3543bb4fc55902a70..ba8b172ddccbac7d8888919f473c43e6257f82db 100644 --- a/system/main/bte_main.c +++ b/system/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/system/main/stack_config.c b/system/main/stack_config.c index 53dda7284464c60aa171d15f5bd87ee828667c79..cbc1c71ad7b3363853aee8d3f9b39db3a8838c3b 100644 --- a/system/main/stack_config.c +++ b/system/main/stack_config.c @@ -35,7 +35,12 @@ static config_t *config; // 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/system/osi/BUILD.gn b/system/osi/BUILD.gn index 3284aaf48d8dcf624e3b4e298e9e3a1f5ef24406..5139dc09863f737f38c5d0ac080d6e481250ffba 100644 --- a/system/osi/BUILD.gn +++ b/system/osi/BUILD.gn @@ -32,6 +32,7 @@ static_library("osi") { "src/list.c", "src/non_repeating_timer.c", "src/reactor.c", + "src/ringbuffer.c", "src/semaphore.c", "src/socket.c", @@ -65,6 +66,7 @@ executable("net_test_osi") { "test/hash_map_test.cpp", "test/list_test.cpp", "test/reactor_test.cpp", + "test/ringbuffer_test.cpp", "test/thread_test.cpp", ] diff --git a/system/service/Android.mk b/system/service/Android.mk index a946d51b1b42002ca2fd7db55a86d716b6c9520c..64856d14672d5e03e4caebe9177a0e51418f2f42 100644 --- a/system/service/Android.mk +++ b/system/service/Android.mk @@ -39,8 +39,9 @@ LOCAL_C_INCLUDES += \ 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/system/service/BUILD.gn b/system/service/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..4beeaedee12c14e93e3880e89c9683bf224d52b5 --- /dev/null +++ b/system/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/system/service/a2dp_source.cpp b/system/service/a2dp_source.cpp index ea01188d2274255d537f691314b93459ab9c1353..1b21cc1dc4121ff6f7527272f44e02c0dd9510a2 100644 --- a/system/service/a2dp_source.cpp +++ b/system/service/a2dp_source.cpp @@ -26,12 +26,12 @@ namespace { 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/system/service/core_stack.cpp b/system/service/core_stack.cpp index 5e63c36d4fcf5cfcb41efa485fbcaf01c9f591b6..f5f94f39378e34845a4d075efa9d73a9e755487b 100644 --- a/system/service/core_stack.cpp +++ b/system/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> + +// TODO(armansito): Remove this line and use base/logging.h instead. +#define LOG_TAG "bluetooth_daemon" -#include "hardware/bluetooth.h" -#include "hardware/hardware.h" #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 @@ bool CoreStack::Initialize() { // 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/system/service/gatt_server.cpp b/system/service/gatt_server.cpp index 03aa54573fb658e566edee3b09459db73fe07582..f2f56e28e26c012240cfe45c06678e746a2e1078 100644 --- a/system/service/gatt_server.cpp +++ b/system/service/gatt_server.cpp @@ -47,7 +47,27 @@ const size_t kMaxGattAttributeSize = 512; 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 @@ struct ServerInternals { 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 @@ void RegisterServerCallback(int status, int server_if, bt_uuid_t *app_uuid) { 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 @@ void ServiceAddedCallback(int status, int server_if, btgatt_srvc_id_t *srvc_id, 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 @@ void RequestReadCallback(int conn_id, int trans_id, bt_bdaddr_t *bda, 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 @@ void RequestWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda, __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 @@ void RequestWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda, // 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 @@ void RequestExecWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda, // 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 @@ void ConnectionCallback(int conn_id, int server_if, int connected, 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 @@ void ServiceStartedCallback(int status, int server_if, int srvc_handle) { // 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 ServiceStartedCallback(int status, int server_if, int srvc_handle) { 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 @@ void RegisterClientCallback(int status, int client_if, bt_uuid_t *app_uuid) { // 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 RegisterClientCallback(int status, int client_if, bt_uuid_t *app_uuid) { 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 @@ int ServerInternals::Initialize(CoreStack *bt) { 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 @@ bool Server::Initialize(const Uuid &service_id, int *gatt_pipe, CoreStack *bt) { 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 @@ bool Server::SetAdvertisement(const std::vector<Uuid> &ids, 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 @@ bool Server::SetScanResponse(const std::vector<Uuid> &ids, 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 @@ bool Server::SetScanResponse(const std::vector<Uuid> &ids, 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 @@ bool Server::Start() { 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 @@ bool Server::Stop() { 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::GetScanResults(ScanResults *results) { 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/system/service/gatt_server.h b/system/service/gatt_server.h index 2328395b29ac9e8a6db7b3f801474d96b4488e0e..c61399a5048be94c3d0b5654267fb09993974bfe 100644 --- a/system/service/gatt_server.h +++ b/system/service/gatt_server.h @@ -53,7 +53,10 @@ const int kPropertyExtendedProps = 0x80; // 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/system/service/host.cpp b/system/service/host.cpp index a6bc375228dd447038d99c7b62d7ec9e2fb0a3fe..af3c2c5d4c66407da7c2733878609c878ea40f63 100644 --- a/system/service/host.cpp +++ b/system/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 @@ bool Host::OnSetAdvertisement(const std::string& service_uuid, 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 @@ bool Host::OnMessage() { 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 @@ bool Host::OnMessage() { 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/system/service/main.cpp b/system/service/main.cpp index cb536eb9b47e7ec9eb3a71b7bae8a4e37ef02f6e..46bff4aefe3fbe6018eaf39f71821c78cc9873cf 100644 --- a/system/service/main.cpp +++ b/system/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 @@ int main() { } close(server_socket); + return EXIT_SUCCESS; } diff --git a/system/service/uuid.cpp b/system/service/uuid.cpp index 13e21a14884ec032eec50f3897c622b00725d063..c48ba5e08726ccfc4b722fd2d46e02767a3e0357 100644 --- a/system/service/uuid.cpp +++ b/system/service/uuid.cpp @@ -24,8 +24,8 @@ namespace bluetooth { 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() {