--- /dev/null
+buildtools
+out
+third_party
--- /dev/null
+#
+# 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.
+#
+
+# This file is used by the GN meta build system to find the root of the source
+# tree and to set startup options. For documentation on the values set in this
+# file, run "gn help dotfile" at the command line.
+
+buildconfig = "//build/config/BUILDCONFIG.gn"
+secondary_source = "//build/secondary/"
bdroid_CFLAGS += -DBLUEDROID_DEBUG
endif
+bdroid_CFLAGS += -DEXPORT_SYMBOL="__attribute__((visibility(\"default\")))"
+
bdroid_CFLAGS += \
+ -fvisibility=hidden \
-Wall \
- -Wno-unused-parameter \
-Wunused-but-set-variable \
-UNDEBUG \
-DLOG_NDEBUG=1
--- /dev/null
+#
+# 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.
+#
+
+# This is the root build file for GN. GN will start processing by loading this
+# file, and recursively load all dependencies until all dependencies are either
+# resolved or known not to exist (which will cause the build to fail). So if
+# you add a new build file, there must be some path of dependencies from this
+# file to your new one or GN won't know about it.
+
+# This pulls in main/BUILD.gn and all of its dependencies.
+group("bluetooth") {
+ deps = [
+ "//main:bluetooth.default",
+ "//service:bluetoothtbd",
+ "//vendor_libs:vendor-libs"
+ ]
+}
--- /dev/null
+Building with GN+ninja
+======================
+
+system/bt is buildable using the GN and and ninja buildtools from the Chromium
+project. After setting up these tools, several third_party packages need to be
+set up to build the stack. It's a simple matter of copying (or sym-linking) some
+packages out of AOSP into "system/bt/third_party":
+
+From AOSP:
+1. "platform/external/libevent" => third_party/libevent. The relevant
+ headers here are "event.h" and "event-config.h". event-config.h from
+ external/libevent is only compatible on Android; this means that you will need
+ to generate a new one based on the current platform. Please follow the
+ instructions in external/libevent/README.android for instructions on how to
+ generate this file.
+2. "platform/external/libchrome" => third_party/libchrome. After that, remove
+the BUILD.gn file that's in libchrome/base. This is a legacy file that only
+works inside the Chromium project and we're using our own from secondary build
+sources.
+3. "platform/external/modp_b64" => third_party/modp_b64
+4. "platform/external/tinyxml2" => third_party/tinyxml2
+
+From Chromium:
+1. "src/testing/gtest" => third_party/gtest
+
+You will also need a fresh checkout of platform/hardware/libhardware and
+platform/system/core for some include dependencies.
+
+BUILD.gn files for all of these packages have already been set up under
+"system/bt/build/secondary/third_party" (note: we don't have a BUILD.gn file for
+modp_b64 since it comes with its own; as the package was imported into AOSP from
+Chromium). To build, run:
+
+1. 'gn args out/Default': This will prompt you to fill the contents of your
+"args.gn" file. Set the two following variables:
+ a. libhw_include_path=<path to your "platform/hardware/libhardware/include">
+ b. core_include_path=<path to your "platform/system/core/include">
+
+Once done, this will create the *.ninja files for the entire project.
+
+2. 'ninja -C out/Default all': This will build all targets (the shared library,
+executables, tests, etc) and put them in out/Default (or whatever you named the
+output directory. To build an individual target, replace "all" with the target
+of your choice, e.g. 'ninja -C out/Default net_test_osi'.
LOCAL_MODULE := audio.a2dp.default
LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SHARED_LIBRARIES := libcutils liblog
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_STATIC_LIBRARIES := libosi
LOCAL_MODULE_TAGS := optional
--- /dev/null
+#
+# 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.
+#
+
+shared_library("audio.a2dp.default") {
+ sources = [
+ "audio_a2dp_hw.c"
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//utils/include",
+ ]
+}
*
*****************************************************************************/
+#define LOG_TAG "bt_a2dp_hw"
+
#include <errno.h>
+#include <fcntl.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdint.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/poll.h>
#include <sys/errno.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/un.h>
#include <unistd.h>
-#include <fcntl.h>
-#include <cutils/str_parms.h>
-#include <cutils/sockets.h>
-#include <system/audio.h>
#include <hardware/audio.h>
-
#include <hardware/hardware.h>
+#include <system/audio.h>
+
#include "audio_a2dp_hw.h"
#include "bt_utils.h"
-
-#define LOG_TAG "bt_a2dp_hw"
+#include "osi/include/hash_map.h"
+#include "osi/include/hash_map_utils.h"
#include "osi/include/log.h"
+#include "osi/include/socket_utils/sockets.h"
/*****************************************************************************
** Constants & Macros
#define CASE_RETURN_STR(const) case const: return #const;
-#define FNLOG() LOG_VERBOSE("%s", __FUNCTION__);
-#define DEBUG(fmt, ...) LOG_VERBOSE("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
-#define INFO(fmt, ...) LOG_INFO("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
-#define ERROR(fmt, ...) LOG_ERROR("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define FNLOG() LOG_VERBOSE(LOG_TAG, "%s", __FUNCTION__);
+#define DEBUG(fmt, ...) LOG_VERBOSE(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define INFO(fmt, ...) LOG_INFO(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define ERROR(fmt, ...) LOG_ERROR(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
#define ASSERTC(cond, msg, val) if (!(cond)) {ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
{
int ret;
int skt_fd;
- struct sockaddr_un remote;
int len;
INFO("connect to %s (sz %zu)", path, buffer_sz);
skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
- if(socket_local_client_connect(skt_fd, path,
+ if(osi_socket_local_client_connect(skt_fd, path,
ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0)
{
ERROR("failed to connect (%s)", strerror(errno));
static int skt_read(int fd, void *p, size_t len)
{
int read;
- struct pollfd pfd;
- struct timespec ts;
FNLOG();
static int a2dp_read_audio_config(struct a2dp_stream_common *common)
{
- char cmd = A2DP_CTRL_GET_AUDIO_CONFIG;
uint32_t sample_rate;
uint8_t channel_count;
static int out_set_format(struct audio_stream *stream, audio_format_t format)
{
+ UNUSED(stream);
UNUSED(format);
- struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
DEBUG("setting format not yet supported (0x%x)", format);
return -ENOSYS;
}
static int out_dump(const struct audio_stream *stream, int fd)
{
+ UNUSED(stream);
UNUSED(fd);
- struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
FNLOG();
return 0;
}
static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
- struct str_parms *parms;
- char keyval[16];
- int retval;
- int status = 0;
INFO("state %d", out->common.state);
- parms = str_parms_create_str(kvpairs);
+ hash_map_t *params = hash_map_utils_new_from_string_params(kvpairs);
+ int status = 0;
+
+ if (!params)
+ return status;
+
+ pthread_mutex_lock(&out->common.lock);
/* dump params */
- str_parms_dump(parms);
+ hash_map_utils_dump_string_keys_string_values(params);
- retval = str_parms_get_str(parms, "closing", keyval, sizeof(keyval));
+ char *keyval = (char *)hash_map_get(params, "closing");
- if (retval >= 0)
+ if (keyval && strcmp(keyval, "true") == 0)
{
- if (strcmp(keyval, "true") == 0)
- {
- DEBUG("stream closing, disallow any writes");
- pthread_mutex_lock(&out->common.lock);
- out->common.state = AUDIO_A2DP_STATE_STOPPING;
- pthread_mutex_unlock(&out->common.lock);
- }
+ DEBUG("stream closing, disallow any writes");
+ out->common.state = AUDIO_A2DP_STATE_STOPPING;
}
- retval = str_parms_get_str(parms, "A2dpSuspended", keyval, sizeof(keyval));
+ keyval = (char *)hash_map_get(params, "A2dpSuspended");
- if (retval >= 0)
+ if (keyval && strcmp(keyval, "true") == 0)
{
- pthread_mutex_lock(&out->common.lock);
- if (strcmp(keyval, "true") == 0)
- {
- if (out->common.state == AUDIO_A2DP_STATE_STARTED)
- status = suspend_audio_datapath(&out->common, false);
- }
- else
- {
- /* Do not start the streaming automatically. If the phone was streaming
- * prior to being suspended, the next out_write shall trigger the
- * AVDTP start procedure */
- if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED)
- out->common.state = AUDIO_A2DP_STATE_STANDBY;
- /* Irrespective of the state, return 0 */
- }
- pthread_mutex_unlock(&out->common.lock);
+ if (out->common.state == AUDIO_A2DP_STATE_STARTED)
+ status = suspend_audio_datapath(&out->common, false);
+ }
+ else
+ {
+ /* Do not start the streaming automatically. If the phone was streaming
+ * prior to being suspended, the next out_write shall trigger the
+ * AVDTP start procedure */
+ if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED)
+ out->common.state = AUDIO_A2DP_STATE_STANDBY;
+ /* Irrespective of the state, return 0 */
}
- str_parms_destroy(parms);
+ pthread_mutex_unlock(&out->common.lock);
+ hash_map_free(params);
return status;
}
static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
{
+ UNUSED(stream);
UNUSED(keys);
- struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
-
FNLOG();
/* add populating param here */
struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
struct a2dp_stream_out *out;
int ret = 0;
- int i;
UNUSED(address);
UNUSED(handle);
UNUSED(devices);
static char * adev_get_parameters(const struct audio_hw_device *dev,
const char *keys)
{
- struct str_parms *parms;
UNUSED(dev);
FNLOG();
- parms = str_parms_create_str(keys);
-
- str_parms_dump(parms);
-
- str_parms_destroy(parms);
+ hash_map_t *params = hash_map_utils_new_from_string_params(keys);
+ hash_map_utils_dump_string_keys_string_values(params);
+ hash_map_free(params);
return strdup("");
}
static int adev_init_check(const struct audio_hw_device *dev)
{
- struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device*)dev;
-
+ UNUSED(dev);
FNLOG();
return 0;
hw_device_t** device)
{
struct a2dp_audio_device *adev;
- int ret;
INFO(" adev_open in A2dp_hw module");
FNLOG();
--- /dev/null
+#
+# 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.
+#
+
+static_library("bta") {
+ sources = [
+ "ag/bta_ag_act.c",
+ "ag/bta_ag_api.c",
+ "ag/bta_ag_at.c",
+ "ag/bta_ag_cfg.c",
+ "ag/bta_ag_ci.c",
+ "ag/bta_ag_cmd.c",
+ "ag/bta_ag_main.c",
+ "ag/bta_ag_rfc.c",
+ "ag/bta_ag_sco.c",
+ "ag/bta_ag_sdp.c",
+ "ar/bta_ar.c",
+ "av/bta_av_aact.c",
+ "av/bta_av_act.c",
+ "av/bta_av_api.c",
+ "av/bta_av_cfg.c",
+ "av/bta_av_ci.c",
+ "av/bta_av_main.c",
+ "av/bta_av_sbc.c",
+ "av/bta_av_ssm.c",
+ "dm/bta_dm_act.c",
+ "dm/bta_dm_api.c",
+ "dm/bta_dm_cfg.c",
+ "dm/bta_dm_ci.c",
+ "dm/bta_dm_main.c",
+ "dm/bta_dm_pm.c",
+ "dm/bta_dm_sco.c",
+ "gatt/bta_gattc_act.c",
+ "gatt/bta_gattc_api.c",
+ "gatt/bta_gattc_cache.c",
+ "gatt/bta_gattc_ci.c",
+ "gatt/bta_gattc_main.c",
+ "gatt/bta_gattc_utils.c",
+ "gatt/bta_gatts_act.c",
+ "gatt/bta_gatts_api.c",
+ "gatt/bta_gatts_main.c",
+ "gatt/bta_gatts_utils.c",
+ "hf_client/bta_hf_client_act.c",
+ "hf_client/bta_hf_client_api.c",
+ "hf_client/bta_hf_client_at.c",
+ "hf_client/bta_hf_client_cmd.c",
+ "hf_client/bta_hf_client_main.c",
+ "hf_client/bta_hf_client_rfc.c",
+ "hf_client/bta_hf_client_sdp.c",
+ "hf_client/bta_hf_client_sco.c",
+ "hh/bta_hh_act.c",
+ "hh/bta_hh_api.c",
+ "hh/bta_hh_cfg.c",
+ "hh/bta_hh_le.c",
+ "hh/bta_hh_main.c",
+ "hh/bta_hh_utils.c",
+ "hl/bta_hl_act.c",
+ "hl/bta_hl_api.c",
+ "hl/bta_hl_ci.c",
+ "hl/bta_hl_main.c",
+ "hl/bta_hl_sdp.c",
+ "hl/bta_hl_utils.c",
+ "jv/bta_jv_act.c",
+ "jv/bta_jv_api.c",
+ "jv/bta_jv_cfg.c",
+ "jv/bta_jv_main.c",
+ "mce/bta_mce_act.c",
+ "mce/bta_mce_api.c",
+ "mce/bta_mce_cfg.c",
+ "mce/bta_mce_main.c",
+ "pan/bta_pan_act.c",
+ "pan/bta_pan_api.c",
+ "pan/bta_pan_ci.c",
+ "pan/bta_pan_main.c",
+ "sdp/bta_sdp.c",
+ "sdp/bta_sdp_act.c",
+ "sdp/bta_sdp_api.c",
+ "sdp/bta_sdp_cfg.c",
+ "sys/bta_sys_conn.c",
+ "sys/bta_sys_main.c",
+ "sys/utl.c",
+ ]
+
+ include_dirs = [
+ "dm",
+ "hh",
+ "include",
+ "sys",
+ "//",
+ "//btcore/include",
+ "//gki/common",
+ "//gki/ulinux",
+ "//hci/include",
+ "//include",
+ "//stack/include",
+ "//stack/btm",
+ "//osi/include",
+ "//udrv/include",
+ "//utils/include",
+ "//vnd/include",
+ ]
+}
p_scb->codec_updated = FALSE;
#endif
/* set up timers */
- p_scb->act_timer.param = (UINT32) p_scb;
+ p_scb->act_timer.param = p_scb;
p_scb->act_timer.p_cback = bta_ag_timer_cback;
#if (BTM_WBS_INCLUDED == TRUE)
/* set eSCO mSBC setting to T2 as the preferred */
/* Start timer to han */
p_scb->colli_timer.p_cback = (TIMER_CBACK*)&bta_ag_colli_timer_cback;
- p_scb->colli_timer.param = (INT32)p_scb;
+ p_scb->colli_timer.param = p_scb;
bta_sys_start_timer(&p_scb->colli_timer, 0, BTA_AG_COLLISION_TIMER);
p_scb->colli_tmr_on = TRUE;
}
/* Start timer to handle timeout */
p_scb->cn_timer.p_cback = (TIMER_CBACK*)&bta_ag_cn_timer_cback;
- p_scb->cn_timer.param = (INT32)p_scb;
+ p_scb->cn_timer.param = p_scb;
bta_sys_start_timer(&p_scb->cn_timer, 0, BTA_AG_CODEC_NEGO_TIMEOUT);
}
else
*
******************************************************************************/
+#define LOG_TAG "bt_bta_av"
+
#include "bt_target.h"
+
#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
#include <string.h>
+
+#include "avdt_api.h"
#include "bta_av_api.h"
#include "bta_av_int.h"
-#include "avdt_api.h"
-#include "utl.h"
#include "l2c_api.h"
#include "osi/include/list.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#include "bta_ar_api.h"
#endif
-#define LOG_TAG "bt_bta_av"
#include "osi/include/log.h"
/*****************************************************************************
}
}
-
/*******************************************************************************
**
** Function bta_av_close_all_rc
/* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL */
ccb.control = p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | AVRC_CT_PASSIVE);
-
if (AVRC_Open(&rc_handle, &ccb, bda) != AVRC_SUCCESS)
return BTA_AV_RC_HANDLE_NONE;
p_scb->rc_handle = p_data->rc_conn_chg.handle;
APPL_TRACE_DEBUG("bta_av_rc_opened shdl:%d, srch %d", i + 1, p_scb->rc_handle);
shdl = i+1;
- LOG_INFO("%s allow incoming AVRCP connections:%d", __func__, p_scb->use_rc);
+ LOG_INFO(LOG_TAG, "%s allow incoming AVRCP connections:%d", __func__, p_scb->use_rc);
bta_sys_stop_timer(&p_scb->timer);
disc = p_scb->hndl;
break;
return;
}
-
if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0)
{
/* rc is opened on the RC only ACP channel, but is for a specific
}
-
/*******************************************************************************
**
** Function bta_av_rc_remote_cmd
UNUSED(p_data);
}
-
-
/*******************************************************************************
**
** Function bta_av_chk_notif_evt_id
}
break;
-
case AVRC_PDU_REGISTER_NOTIFICATION:
/* make sure the event_id is implemented */
p_rc_rsp->rsp.status = bta_av_chk_notif_evt_id (p_vendor);
return evt;
}
-
/*******************************************************************************
**
** Function bta_av_rc_msg
}
}
-
/*******************************************************************************
**
** Function bta_av_conn_chg
bta_av_cb.audio_open_cnt++;
}
-
APPL_TRACE_DEBUG("rc_acp_handle:%d rc_acp_idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx);
/* check if the AVRCP ACP channel is already connected */
if(p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE && p_cb->rc_acp_idx)
/* Possible collision : need to avoid outgoing processing while the timer is running */
p_cb->p_scb[xx]->coll_mask = BTA_AV_COLL_INC_TMR;
- p_cb->acp_sig_tmr.param = (UINT32)xx;
+ // TODO(armansito): Why is this variable called "xx" and
+ // why is it a signed integer? The callback reinterprets
+ // it as a UINT8 and then reassigns it as param that
+ // way, so should this be unsigned?
+ p_cb->acp_sig_tmr.param = INT_TO_PTR(xx);
p_cb->acp_sig_tmr.p_cback = (TIMER_CBACK*)&bta_av_acp_sig_timer_cback;
bta_sys_start_timer(&p_cb->acp_sig_tmr, 0, BTA_AV_ACP_SIG_TIME_VAL);
}
*******************************************************************************/
static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle)
{
- UINT8 inx = (UINT8)p_tle->param;
+ UINT8 inx = PTR_TO_UINT(p_tle->param);
tBTA_AV_CB *p_cb = &bta_av_cb;
tBTA_AV_SCB *p_scb = NULL;
tBTA_AV_API_OPEN *p_buf;
/* We are still doing SDP. Run the timer again. */
p_scb->coll_mask |= BTA_AV_COLL_INC_TMR;
- p_cb->acp_sig_tmr.param = (UINT32)inx;
+ p_cb->acp_sig_tmr.param = UINT_TO_PTR(inx);
p_cb->acp_sig_tmr.p_cback = (TIMER_CBACK *)&bta_av_acp_sig_timer_cback;
bta_sys_start_timer(&p_cb->acp_sig_tmr, 0, BTA_AV_ACP_SIG_TIME_VAL);
}
*
******************************************************************************/
+#define LOG_TAG "bt_bta_av"
+
#include <assert.h>
#include <string.h>
#include "osi/include/log.h"
#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE)
+#include "bta_av_co.h"
#include "bta_av_int.h"
-#include "utl.h"
#include "l2c_api.h"
#include "l2cdefs.h"
-#include "bta_av_co.h"
+#include "utl.h"
+
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#include "bta_ar_api.h"
#endif
app_id, BD_ADDR peer_addr);
static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
-
/* action functions */
const tBTA_AV_NSM_ACT bta_av_nsm_act[] =
{
}
/*******************************************************************************
-**
-** Function bta_av_free_scb
-**
-** Description free stream control block,
-**
-**
-** Returns void
-**
-*******************************************************************************/
-static void bta_av_free_scb(tBTA_AV_SCB *p_scb)
-{
- // NOTE(google) This free currently is not called
- assert(p_scb != NULL);
-
- list_free(p_scb->a2d_list);
- GKI_freebuf(p_scb);
-}
-
-/*******************************************************************************
*******************************************************************************/
void bta_av_conn_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data)
{
if (BTM_GetRole(p_scb->peer_addr, &role) == BTM_SUCCESS)
{
- LOG_INFO("%s hndl:x%x role:%d conn_audio:x%x bits:%d features:x%x",
+ LOG_INFO(LOG_TAG, "%s hndl:x%x role:%d conn_audio:x%x bits:%d features:x%x",
__func__, p_scb->hndl, role, bta_av_cb.conn_audio, bits,
bta_av_cb.features);
if (BTM_ROLE_MASTER != role && (A2D_BitsSet(bta_av_cb.conn_audio) > bits || (bta_av_cb.features & BTA_AV_FEAT_MASTER)))
}
}
-
/*******************************************************************************
**
** Function bta_av_hdl_event
return TRUE;
}
-
/*****************************************************************************
** Debug Functions
*****************************************************************************/
*
******************************************************************************/
+#define LOG_TAG "bt_bta_dm"
+
+#include <string.h>
+
#include "bt_target.h"
#include "bt_types.h"
-#include "gki.h"
-#include "bta_sys.h"
#include "bta_api.h"
-#include "bta_dm_int.h"
#include "bta_dm_co.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
-#include "sdp_api.h"
-#include "l2c_api.h"
-#include "utl.h"
#include "gap_api.h" /* For GAP_BleReadPeerPrefConnParams */
-#include <string.h>
-
-#define LOG_TAG "bt_bta_dm"
+#include "gki.h"
+#include "l2c_api.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "utl.h"
#if (GAP_INCLUDED == TRUE)
#include "gap_api.h"
else
{
bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_timer_cback;
- bta_dm_cb.disable_timer.param = 0;
+ bta_dm_cb.disable_timer.param = INT_TO_PTR(0);
bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 5000);
}
APPL_TRACE_EVENT(" bta_dm_disable_timer_cback trial %d ", p_tle->param);
- if(BTM_GetNumAclLinks() && p_tle->param == 0)
+ if(BTM_GetNumAclLinks() && PTR_TO_INT(p_tle->param) == 0)
{
for(i=0; i<bta_dm_cb.device_list.count; i++)
{
if (trigger_disc)
{
bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_timer_cback;
- bta_dm_cb.disable_timer.param = 1;
+ bta_dm_cb.disable_timer.param = INT_TO_PTR(1);
bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 1500);
}
}
{
tSDP_UUID uuid;
- UINT16 num_attrs = 1;
tBTA_DM_MSG *p_msg;
memset (&uuid, 0, sizeof(tSDP_UUID));
/* try to search all services by search based on L2CAP UUID */
if(bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK )
{
- LOG_INFO("%s services_to_search=%08x", __func__, bta_dm_search_cb.services_to_search);
+ LOG_INFO(LOG_TAG, "%s services_to_search=%08x", __func__, bta_dm_search_cb.services_to_search);
if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK)
{
uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[0];
memcpy(&uuid, &bta_dm_search_cb.uuid, sizeof(tSDP_UUID));
}
- LOG_INFO("%s search UUID = %04x", __func__, uuid.uu.uuid16);
+ LOG_INFO(LOG_TAG, "%s search UUID = %04x", __func__, uuid.uu.uuid16);
SDP_InitDiscoveryDb (bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, &uuid, 0, NULL);
memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
tBTM_STATUS status = BTM_SUCCESS;
tBTA_DM_SEC sec_event;
char *p_name = NULL;
- UINT8 i;
- tBT_DEVICE_TYPE dev_type;
if (!bta_dm_cb.p_sec_cback)
return BTM_NOT_AUTHORIZED;
tBTA_STATUS status = BTA_FAILURE;
if (BTM_BleWriteAdvData(p_data->ble_set_adv_data.data_mask,
- (tBTM_BLE_ADV_DATA *)p_data->ble_set_adv_data.p_adv_cfg) == BTM_SUCCESS)
+ (tBTM_BLE_ADV_DATA *)&p_data->ble_set_adv_data.adv_cfg) == BTM_SUCCESS)
{
status = BTA_SUCCESS;
}
tBTA_STATUS status = BTA_FAILURE;
if(BTM_BleWriteScanRsp(p_data->ble_set_adv_data.data_mask,
- (tBTM_BLE_ADV_DATA *)p_data->ble_set_adv_data.p_adv_cfg) == BTM_SUCCESS)
+ (tBTM_BLE_ADV_DATA *)&p_data->ble_set_adv_data.adv_cfg) == BTM_SUCCESS)
{
status = BTA_SUCCESS;
}
btm_status = BTM_BleCfgAdvInstData(p_data->ble_multi_adv_data.inst_id,
p_data->ble_multi_adv_data.is_scan_rsp,
p_data->ble_multi_adv_data.data_mask,
- (tBTM_BLE_ADV_DATA*)p_data->ble_multi_adv_data.p_data);
+ (tBTM_BLE_ADV_DATA*)&p_data->ble_multi_adv_data.data);
}
if(BTM_CMD_STARTED != btm_status)
APPL_TRACE_ERROR("%s out of room to accomodate more service ids ble_raw_size = %d ble_raw_used = %d", __FUNCTION__,bta_dm_search_cb.ble_raw_size, bta_dm_search_cb.ble_raw_used );
}
- LOG_INFO("%s service_id_uuid_len=%d ", __func__, service_id.uuid.len);
+ LOG_INFO(LOG_TAG, "%s service_id_uuid_len=%d ", __func__, service_id.uuid.len);
if ( bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE)
{
void BTA_DmBleSetAdvConfig (tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA *p_adv_cfg,
tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback)
{
- tBTA_DM_API_SET_ADV_CONFIG *p_msg;
-
- if ((p_msg = (tBTA_DM_API_SET_ADV_CONFIG *)
- GKI_getbuf(sizeof(tBTA_DM_API_SET_ADV_CONFIG))) != NULL)
- {
- p_msg->hdr.event = BTA_DM_API_BLE_SET_ADV_CONFIG_EVT;
- p_msg->data_mask = data_mask;
- p_msg->p_adv_data_cback = p_adv_data_cback;
- p_msg->p_adv_cfg = p_adv_cfg;
-
- bta_sys_sendmsg(p_msg);
- }
+ tBTA_DM_API_SET_ADV_CONFIG *p_msg = GKI_getbuf(sizeof(*p_msg));
+ if (!p_msg) return;
+
+ memset(p_msg, 0, sizeof(*p_msg));
+ p_msg->hdr.event = BTA_DM_API_BLE_SET_ADV_CONFIG_EVT;
+ p_msg->data_mask = data_mask;
+ p_msg->p_adv_data_cback = p_adv_data_cback;
+ memcpy(&p_msg->adv_cfg, p_adv_cfg, sizeof(p_msg->adv_cfg));
+ bta_sys_sendmsg(p_msg);
}
/*******************************************************************************
extern void BTA_DmBleSetScanRsp (tBTA_BLE_AD_MASK data_mask, tBTA_BLE_ADV_DATA *p_adv_cfg,
tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback)
{
- tBTA_DM_API_SET_ADV_CONFIG *p_msg;
-
- if ((p_msg = (tBTA_DM_API_SET_ADV_CONFIG *)
- GKI_getbuf(sizeof(tBTA_DM_API_SET_ADV_CONFIG))) != NULL)
- {
- p_msg->hdr.event = BTA_DM_API_BLE_SET_SCAN_RSP_EVT;
- p_msg->data_mask = data_mask;
- p_msg->p_adv_data_cback = p_adv_data_cback;
- p_msg->p_adv_cfg = p_adv_cfg;
-
- bta_sys_sendmsg(p_msg);
- }
+ tBTA_DM_API_SET_ADV_CONFIG *p_msg = GKI_getbuf(sizeof(*p_msg));
+ if (!p_msg) return;
+
+ memset(p_msg, 0, sizeof(*p_msg));
+ p_msg->hdr.event = BTA_DM_API_BLE_SET_SCAN_RSP_EVT;
+ p_msg->data_mask = data_mask;
+ p_msg->p_adv_data_cback = p_adv_data_cback;
+ memcpy(&p_msg->adv_cfg, p_adv_cfg, sizeof(p_msg->adv_cfg));
+ bta_sys_sendmsg(p_msg);
}
/*******************************************************************************
tBTA_BLE_AD_MASK data_mask,
tBTA_BLE_ADV_DATA *p_data)
{
- tBTA_DM_API_BLE_MULTI_ADV_DATA *p_msg;
- UINT16 len = sizeof(tBTA_DM_API_BLE_MULTI_ADV_DATA) ;
-
- APPL_TRACE_API ("BTA_BleCfgAdvInstData");
-
- if ((p_msg = (tBTA_DM_API_BLE_MULTI_ADV_DATA *) GKI_getbuf(len)) != NULL)
- {
- memset(p_msg, 0, len);
- p_msg->hdr.event = BTA_DM_API_BLE_MULTI_ADV_DATA_EVT;
- p_msg->inst_id = inst_id;
- p_msg->is_scan_rsp = is_scan_rsp;
- p_msg->data_mask = data_mask;
- p_msg->p_data = p_data;
-
- bta_sys_sendmsg(p_msg);
- }
+ tBTA_DM_API_BLE_MULTI_ADV_DATA *p_msg = GKI_getbuf(sizeof(*p_msg));
+ if (!p_msg) return;
+
+ memset(p_msg, 0, sizeof(*p_msg));
+ p_msg->hdr.event = BTA_DM_API_BLE_MULTI_ADV_DATA_EVT;
+ p_msg->inst_id = inst_id;
+ p_msg->is_scan_rsp = is_scan_rsp;
+ p_msg->data_mask = data_mask;
+ memcpy(&p_msg->data, p_data, sizeof(p_msg->data));
+ bta_sys_sendmsg(p_msg);
}
/*******************************************************************************
UINT8 inst_id;
BOOLEAN is_scan_rsp;
tBTA_BLE_AD_MASK data_mask;
- tBTA_BLE_ADV_DATA *p_data;
+ tBTA_BLE_ADV_DATA data;
}tBTA_DM_API_BLE_MULTI_ADV_DATA;
typedef struct
{
BT_HDR hdr;
UINT32 data_mask;
- tBTA_BLE_ADV_DATA *p_adv_cfg;
+ tBTA_BLE_ADV_DATA adv_cfg;
tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback;
}tBTA_DM_API_SET_ADV_CONFIG;
{
UINT8 i,j;
- UINT16 policy_setting;
UINT8 *p = NULL;
tBTA_DM_PEER_DEVICE *p_dev;
* machine.
*
******************************************************************************/
-#define LOG_TAG "bt_bta_gattc"
-#include "bt_target.h"
+#define LOG_TAG "bt_bta_gattc"
-#include "utl.h"
-#include "gki.h"
-#include "bta_sys.h"
+#include <string.h>
+#include "bt_target.h"
#include "bta_gattc_int.h"
+#include "bta_sys.h"
+#include "btif/include/btif_debug_conn.h"
+#include "gki.h"
#include "l2c_api.h"
+#include "osi/include/log.h"
+#include "utl.h"
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
#include "bta_hh_int.h"
#endif
-#include "btif/include/btif_debug_conn.h"
-
-#include <string.h>
-
-#include "osi/include/log.h"
-
#if BTA_GATT_INCLUDED && BLE_INCLUDED == TRUE
/*****************************************************************************
}
}
-
/*******************************************************************************
**
** Function bta_gattc_disable
tBTA_GATTC_INT_START_IF *p_buf;
tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
-
APPL_TRACE_DEBUG("bta_gattc_register state %d",p_cb->state);
memset(&cb_data, 0, sizeof(cb_data));
cb_data.reg_oper.status = BTA_GATT_NO_RESOURCES;
cb_data.close.status = BTA_GATT_ERROR;
cb_data.close.reason = BTA_GATT_CONN_NONE;
-
(*p_clcb->p_rcb->p_cback)(BTA_GATTC_CLOSE_EVT, &cb_data);
}
}
utl_freebuf((void **)&p_clcb->p_q_cmd);
-
if (p_data->p_cmpl && p_data->status == BTA_GATT_OK)
p_clcb->p_srcb->mtu = p_data->p_cmpl->mtu;
/* if listen to all */
else
{
- LOG_DEBUG("Listen For All now");
+ LOG_DEBUG(LOG_TAG, "Listen For All now");
/* go through all connected device and send
callback for all connected slave connection */
bta_gattc_process_listen_all(p_msg->api_listen.client_if);
*
******************************************************************************/
+#define LOG_TAG "bt_bta_gattc"
+
#include "bt_target.h"
#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
#include <string.h>
-#include "utl.h"
-#include "gki.h"
-#include "bta_sys.h"
-#include "sdp_api.h"
-#include "sdpdefs.h"
+
#include "bta_gattc_int.h"
+#include "bta_sys.h"
#include "btm_api.h"
#include "btm_ble_api.h"
-
-#define LOG_TAG "bt_bta_gattc"
+#include "gki.h"
#include "osi/include/log.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+#include "utl.h"
static void bta_gattc_char_dscpt_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb);
static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb);
}
}
/* no service found at all, the end of server discovery*/
- LOG_WARN("%s no more services found", __func__);
+ LOG_WARN(LOG_TAG, "%s no more services found", __func__);
#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE)
bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
*
******************************************************************************/
+#define LOG_TAG "bt_bta_gattc"
+
#include "bt_target.h"
#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
#include <string.h>
+#include "bta_gattc_int.h"
+#include "bta_sys.h"
#include "btcore/include/bdaddr.h"
#include "btif/include/btif_util.h"
#include "gki.h"
-#include "utl.h"
-#include "bta_sys.h"
-#include "bta_gattc_int.h"
#include "l2c_api.h"
+#include "utl.h"
-#define LOG_TAG "bt_bta_gattc"
/*****************************************************************************
** Constants
*****************************************************************************/
-
static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
return NULL;
}
-
/*******************************************************************************
**
** Function bta_gattc_conn_find_alloc
#include <string.h>
#include <stdlib.h>
+
+// TODO(armansito): cutils/properties.h is only being used to pull-in runtime
+// settings on Android. Remove this conditional include once we have a generic
+// way to obtain system properties.
+#if !defined(OS_GENERIC)
#include <cutils/properties.h>
+#endif // !defined(OS_GENERIC)
+
#include "bt_utils.h"
#include "bta_api.h"
#include "bta_sys.h"
*******************************************************************************/
static void bta_hf_client_api_enable(tBTA_HF_CLIENT_DATA *p_data)
{
+ // TODO(armansito): For non-Android systems we need a common method of
+ // loading system properties. Remove the conditionally compiled code once we
+ // have that in place.
+#if !defined(OS_GENERIC)
char value[PROPERTY_VALUE_MAX];
+#endif // !defined(OS_GENERIC)
/* initialize control block */
memset(&bta_hf_client_cb, 0, sizeof(tBTA_HF_CLIENT_CB));
/* store callback function */
bta_hf_client_cb.p_cback = p_data->api_enable.p_cback;
+ // TODO(armansito): For non-Android systems we need a common method of
+ // loading system properties. Remove the conditionally compiled code once we
+ // have that in place.
+#if !defined(OS_GENERIC)
/* check if mSBC support enabled */
property_get("ro.bluetooth.hfp.ver", value, "0");
if (strcmp(value,"1.6") == 0)
{
bta_hf_client_cb.msbc_enabled = TRUE;
}
+#endif // !defined(OS_GENERIC)
bta_hf_client_cb.scb.negotiated_codec = BTM_SCO_CODEC_CVSD;
*
******************************************************************************/
+#define LOG_TAG "bt_bta_hh"
+
+#include "bta_hh_api.h"
+
#include "bt_target.h"
#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-#include "bta_hh_api.h"
#include "bta_hh_int.h"
#include "l2c_api.h"
-#include "utl.h"
-
-#define LOG_TAG "bt_bta_hh"
#include "osi/include/log.h"
+#include "utl.h"
/*****************************************************************************
** Constants
/* register with BTA system manager */
bta_sys_register(BTA_ID_HH, &bta_hh_reg);
- LOG_INFO("%s sec_mask:0x%x p_cback:%p", __func__, sec_mask, p_cback);
+ LOG_INFO(LOG_TAG, "%s sec_mask:0x%x p_cback:%p", __func__, sec_mask, p_cback);
p_buf = (tBTA_HH_API_ENABLE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_ENABLE));
if (p_buf != NULL)
*
******************************************************************************/
+#define LOG_TAG "bt_bta_hh"
+
#include "bta_api.h"
#include "bta_hh_int.h"
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
-#include "bta_api.h"
#include <string.h>
+
+#include "bta_api.h"
+#include "bta_gatt_api.h"
+#include "bta_hh_co.h"
#include "btm_api.h"
#include "btm_ble_api.h"
-#include "bta_hh_co.h"
-#include "bta_gatt_api.h"
-#include "srvc_api.h"
#include "btm_int.h"
-#include "utl.h"
-
-#define LOG_TAG "bt_bta_hh"
#include "osi/include/log.h"
+#include "srvc_api.h"
+#include "utl.h"
#ifndef BTA_HH_LE_RECONN
#define BTA_HH_LE_RECONN TRUE
else
{
#if BTA_HH_DEBUG == TRUE
- LOG_WARN("%s No descriptor exists: %s(0x%04x)", __func__,
+ LOG_WARN(LOG_TAG, "%s No descriptor exists: %s(0x%04x)", __func__,
bta_hh_uuid_to_str(char_descp_uuid), char_descp_uuid);
#endif
}
}
while (1);
- LOG_INFO("%s all BLE reports searched", __func__);
+ LOG_INFO(LOG_TAG, "%s all BLE reports searched", __func__);
bta_hh_le_read_rpt_ref_descr(p_dev_cb,
&p_dev_cb->hid_srvc[p_dev_cb->cur_srvc_index].report[0]);
{
return(FALSE);
}
- SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+
item_cnt=0;
for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr && (item_cnt < 4) ; p_sattr = p_sattr->p_next_attr)
for (i=0; i < BTA_HL_NUM_MCLS ; i ++)
{
- BTA_HL_GET_MCL_CB_PTR(app_idx, i);
-
if (bta_hl_cb.acb[app_idx].mcb[i].in_use &&
(!memcmp (bta_hl_cb.acb[app_idx].mcb[i].bd_addr, p_bd_addr, BD_ADDR_LEN)))
{
#define BTA_DM_BLE_AD_BIT_RANDOM_ADDR BTM_BLE_AD_BIT_RANDOM_ADDR
#define BTA_DM_BLE_AD_BIT_SERVICE_128 BTM_BLE_AD_BIT_SERVICE_128 /*128-bit Service UUIDs*/
-typedef tBTM_BLE_AD_MASK tBTA_BLE_AD_MASK;
-
-/* slave preferred connection interval range */
-typedef struct
-{
- UINT16 low;
- UINT16 hi;
-
-}tBTA_BLE_INT_RANGE;
-
-/* Service tag supported in the device */
-typedef struct
-{
- UINT8 num_service;
- BOOLEAN list_cmpl;
- UINT16 *p_uuid;
-}tBTA_BLE_SERVICE;
-
-
-typedef struct
-{
- UINT8 len;
- UINT8 *p_val;
-}tBTA_BLE_MANU;
-
-typedef struct
-{
- UINT8 adv_type;
- UINT8 len;
- UINT8 *p_val; /* number of len byte */
-}tBTA_BLE_PROP_ELEM;
-
-/* vendor proprietary adv type */
-typedef struct
-{
- UINT8 num_elem;
- tBTA_BLE_PROP_ELEM *p_elem;
-}tBTA_BLE_PROPRIETARY;
-
-typedef struct
-{
- tBT_UUID service_uuid;
- UINT8 len;
- UINT8 *p_val;
-}tBTA_BLE_SERVICE_DATA;
-
+typedef tBTM_BLE_AD_MASK tBTA_BLE_AD_MASK;
+typedef tBTM_BLE_INT_RANGE tBTA_BLE_INT_RANGE;
+typedef tBTM_BLE_SERVICE tBTA_BLE_SERVICE;
+typedef tBTM_BLE_PROP_ELEM tBTA_BLE_PROP_ELEM;
+typedef tBTM_BLE_PROPRIETARY tBTA_BLE_PROPRIETARY;
+typedef tBTM_BLE_MANU tBTA_BLE_MANU;
+typedef tBTM_BLE_SERVICE_DATA tBTA_BLE_SERVICE_DATA;
typedef tBTM_BLE_128SERVICE tBTA_BLE_128SERVICE;
typedef tBTM_BLE_32SERVICE tBTA_BLE_32SERVICE;
typedef struct
{
tBTA_BLE_INT_RANGE int_range; /* slave prefered conn interval range */
- tBTA_BLE_MANU *p_manu; /* manufacturer data */
- tBTA_BLE_SERVICE *p_services; /* 16 bits services */
- tBTA_BLE_128SERVICE *p_services_128b; /* 128 bits service */
- tBTA_BLE_32SERVICE *p_service_32b; /* 32 bits Service UUID */
- tBTA_BLE_SERVICE *p_sol_services; /* 16 bits services Solicitation UUIDs */
- tBTA_BLE_32SERVICE *p_sol_service_32b; /* List of 32 bit Service Solicitation UUIDs */
- tBTA_BLE_128SERVICE *p_sol_service_128b;/* List of 128 bit Service Solicitation UUIDs */
- tBTA_BLE_PROPRIETARY *p_proprietary; /* proprietary data */
- tBTA_BLE_SERVICE_DATA *p_service_data; /* service data */
+ tBTA_BLE_MANU manu; /* manufacturer data */
+ tBTA_BLE_SERVICE services; /* 16 bits services */
+ tBTA_BLE_128SERVICE services_128b; /* 128 bits service */
+ tBTA_BLE_32SERVICE service_32b; /* 32 bits Service UUID */
+ tBTA_BLE_SERVICE sol_services; /* 16 bits services Solicitation UUIDs */
+ tBTA_BLE_32SERVICE sol_service_32b; /* List of 32 bit Service Solicitation UUIDs */
+ tBTA_BLE_128SERVICE sol_service_128b;/* List of 128 bit Service Solicitation UUIDs */
+ tBTA_BLE_PROPRIETARY proprietary; /* proprietary data */
+ tBTA_BLE_SERVICE_DATA service_data; /* service data */
UINT16 appearance; /* appearance data */
UINT8 flag;
UINT8 tx_power;
#include <arpa/inet.h>
#include <pthread.h>
#include <stdlib.h>
+#include <string.h>
#include "osi/include/allocator.h"
#include "bt_types.h"
#include "sdp_api.h"
#include "l2c_api.h"
#include "port_api.h"
-#include <string.h>
#include "rfcdefs.h"
#include "avct_api.h"
#include "avdt_api.h"
#include "gap_api.h"
#include "l2c_api.h"
+#include "osi/include/osi.h"
+
/* one of these exists for each client */
struct fc_client {
static struct fc_client *fc_clients;
static struct fc_channel *fc_channels;
static uint32_t fc_next_id;
-static pthread_once_t fc_init_once = PTHREAD_ONCE_INIT;
-
-
-static void fc_init_work(void)
-{
- fc_clients = NULL;
- fc_channels = NULL;
- fc_next_id = 0;
-
- //more init here if needed...
-}
-
-static void fc_init(void)
-{
- pthread_once(&fc_init_once, fc_init_work);
-}
static void fcchan_conn_chng_cbk(UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected,
/* rfc handle bd addr retrieval requires core stack handle */
if (bRfcHandle)
{
- UINT32 hi = ((jv_handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
- UINT32 si = BTA_JV_RFC_HDL_TO_SIDX(jv_handle);
for (j = 0; j < BTA_JV_MAX_RFC_CONN; j++)
{
if (jv_handle == bta_jv_cb.port_cb[j].handle)
static void bta_jv_start_discovery_cback(UINT16 result, void * user_data)
{
tBTA_JV_STATUS status;
- UINT8 old_sdp_act = bta_jv_cb.sdp_active;
APPL_TRACE_DEBUG("bta_jv_start_discovery_cback res: 0x%x", result);
tL2CAP_CFG_INFO cfg;
tBTA_JV_L2CAP_START evt_data;
tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server);
- INT32 use_etm = FALSE;
UINT8 chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
tL2CAP_ERTM_INFO *ertm_info = NULL;
return 1;
}
}
- APPL_TRACE_DEBUG("find_rfc_pcb: cannot find rfc_cb from user data:%d", (UINT32)user_data);
+ APPL_TRACE_DEBUG("find_rfc_pcb: cannot find rfc_cb from user data: %u", PTR_TO_UINT(user_data));
return 0;
}
/*******************************************************************************
**
-** Function bta_jv_get_num_rfc_listen
-**
-** Description when a RFCOMM connection goes down, make sure that there's only
-** one port stays listening on this scn.
-**
-** Returns
-**
-*******************************************************************************/
-static UINT8 bta_jv_get_num_rfc_listen(tBTA_JV_RFC_CB *p_cb)
-{
- UINT8 listen=1;
-
- if (p_cb->max_sess > 1)
- {
- listen = 0;
- for (UINT8 i=0; i<p_cb->max_sess; i++)
- {
- if (p_cb->rfc_hdl[i] != 0)
- {
- const tBTA_JV_PCB *p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1];
- if (BTA_JV_ST_SR_LISTEN == p_pcb->state)
- {
- listen++;
- }
- }
- }
- }
- return listen;
-}
-
-/*******************************************************************************
-**
** Function bta_jv_port_mgmt_sr_cback
**
** Description callback for port mamangement function of rfcomm
static void fcchan_data_cbk(UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf)
{
tBTA_JV evt_data;
- tBTA_JV evt_open;
struct fc_channel *tc;
struct fc_client *t = NULL;
tBTA_JV_L2CAP_CBACK *sock_cback = NULL;
tBTA_JV_API_L2CAP_SERVER *ss = &(p_data->l2cap_server);
tBTA_JV_L2CAP_START evt_data;
struct fc_client *t;
- uint16_t handle;
evt_data.handle = GAP_INVALID_HANDLE;
evt_data.status = BTA_JV_FAILURE;
static void bta_create_mns_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
{
- tSDP_DISCOVERY_DB *db = p_bta_sdp_cfg->p_sdp_db;
tSDP_DISC_ATTR *p_attr;
tSDP_PROTOCOL_ELEM pe;
UINT16 pversion = 0;
- UINT8 offset = 0;
record->mns.hdr.type = SDP_TYPE_MAP_MNS;
record->mns.hdr.service_name_length = 0;
record->mns.hdr.service_name = NULL;
static void bta_create_mas_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
{
- tSDP_DISCOVERY_DB *db = p_bta_sdp_cfg->p_sdp_db;
tSDP_DISC_ATTR *p_attr;
tSDP_PROTOCOL_ELEM pe;
UINT16 pversion = -1;
static void bta_create_pse_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
{
- tSDP_DISCOVERY_DB *db = p_bta_sdp_cfg->p_sdp_db;
tSDP_DISC_ATTR *p_attr;
UINT16 pversion;
tSDP_PROTOCOL_ELEM pe;
static void bta_create_ops_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
{
- tSDP_DISCOVERY_DB *db = p_bta_sdp_cfg->p_sdp_db;
tSDP_DISC_ATTR *p_attr, *p_sattr;
tSDP_PROTOCOL_ELEM pe;
UINT16 pversion = -1;
static void bta_create_raw_sdp_record(bluetooth_sdp_record *record, tSDP_DISC_REC *p_rec)
{
- tSDP_DISCOVERY_DB *db = p_bta_sdp_cfg->p_sdp_db;
tSDP_DISC_ATTR *p_attr;
- UINT16 pversion;
tSDP_PROTOCOL_ELEM pe;
record->hdr.type = SDP_TYPE_RAW;
tSDP_DISC_REC *p_rec = NULL;
tBTA_SDP_SEARCH_COMP evt_data = {0}; // We need to zero-initialize
tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
- UINT16 uuid16 = 0;
int count = 0;
tBT_UUID su;
APPL_TRACE_DEBUG("%s() - res: 0x%x", __func__, result);
* This is the main implementation file for the BTA system manager.
*
******************************************************************************/
+
#define LOG_TAG "bt_bta_sys_main"
#include <assert.h>
+#include <pthread.h>
#include <string.h>
-#include "osi/include/alarm.h"
-#include "btm_api.h"
#include "bta_api.h"
#include "bta_sys.h"
#include "bta_sys_int.h"
-
-#include "osi/include/fixed_queue.h"
+#include "btm_api.h"
#include "gki.h"
-#include "osi/include/hash_map.h"
-#include "osi/include/osi.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
#include "osi/include/hash_functions.h"
+#include "osi/include/hash_map.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/thread.h"
+#include "utl.h"
+
#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE)
#include "bta_ar_api.h"
#endif
-#include "utl.h"
/* system manager control block definition */
#if BTA_DYNAMIC_MEMORY == FALSE
alarm_t *alarm = hash_map_get(bta_alarm_hash_map, p_tle);
if (alarm == NULL) {
- LOG_ERROR("%s unable to create alarm.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create alarm.", __func__);
return;
}
alarm_t *alarm = hash_map_get(bta_alarm_hash_map, p_tle);
if (alarm == NULL) {
- LOG_DEBUG("%s expected alarm was not in bta alarm hash map.", __func__);
+ LOG_DEBUG(LOG_TAG, "%s expected alarm was not in bta alarm hash map.", __func__);
return;
}
alarm_cancel(alarm);
LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# osi/include/atomic.h depends on gcc atomic functions
-LOCAL_CLANG := false
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/include \
- $(LOCAL_PATH)/../osi/include \
- $(LOCAL_PATH)/..
-
-LOCAL_SRC_FILES := \
+# Common variables
+# ========================================================
+btcoreCommonSrc := \
src/bdaddr.c \
src/counter.c \
src/device_class.c \
+ src/hal_util.c \
src/module.c \
src/osi_module.c \
src/property.c \
src/uuid.c
+btcoreCommonTestSrc := \
+ ./test/bdaddr_test.cpp \
+ ./test/counter_test.cpp \
+ ./test/device_class_test.cpp \
+ ./test/property_test.cpp \
+ ./test/uuid_test.cpp \
+ ../osi/test/AllocationTestHarness.cpp
+
+btcoreCommonIncludes := \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../osi/include \
+ $(LOCAL_PATH)/..
+
+# libbtcore static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CLANG_CFLAGS += -Wno-error=typedef-redefinition
+LOCAL_C_INCLUDES := $(btcoreCommonIncludes)
+LOCAL_SRC_FILES := $(btcoreCommonSrc)
LOCAL_CFLAGS := -std=c99 $(bdroid_CFLAGS)
LOCAL_MODULE := libbtcore
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libc liblog
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-
include $(BUILD_STATIC_LIBRARY)
-#####################################################
-
+# libbtcore static library for host
+# ========================================================
+ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
+LOCAL_CLANG_CFLAGS += -Wno-error=typedef-redefinition
+LOCAL_C_INCLUDES := $(btcoreCommonIncludes)
+LOCAL_SRC_FILES := $(btcoreCommonSrc)
+# TODO(armansito): Setting _GNU_SOURCE isn't very platform-independent but
+# should be compatible for a Linux host OS. We should figure out what to do for
+# a non-Linux host OS.
+LOCAL_CFLAGS := -std=c99 $(bdroid_CFLAGS) -D_GNU_SOURCE
+LOCAL_MODULE := libbtcore-host
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+include $(BUILD_HOST_STATIC_LIBRARY)
+endif
-# osi/include/atomic.h depends on gcc atomic functions
-LOCAL_CLANG := false
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/include \
- $(LOCAL_PATH)/..
-
-LOCAL_SRC_FILES := \
- ./test/bdaddr_test.cpp \
- ./test/counter_test.cpp \
- ./test/device_class_test.cpp \
- ./test/property_test.cpp \
- ./test/uuid_test.cpp \
- ../osi/test/AllocationTestHarness.cpp
+# Note: It's good to get the tests compiled both for the host and the target so
+# we get to test with both Bionic libc and glibc
+# libbtcore unit tests for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CLANG_CFLAGS += -Wno-error=typedef-redefinition
+LOCAL_C_INCLUDES := $(btcoreCommonIncludes)
+LOCAL_SRC_FILES := $(btcoreCommonTestSrc)
LOCAL_CFLAGS := -Wall -Werror -Werror=unused-variable
LOCAL_MODULE := net_test_btcore
-
LOCAL_MODULE_TAGS := tests
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_STATIC_LIBRARIES := libbtcore libosi
-
include $(BUILD_NATIVE_TEST)
+
+# libbtcore unit tests for host
+# ========================================================
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_CLANG_CFLAGS += -Wno-error=typedef-redefinition
+LOCAL_C_INCLUDES := $(btcoreCommonIncludes)
+LOCAL_SRC_FILES := $(btcoreCommonTestSrc)
+LOCAL_CFLAGS := -Wall -Werror -Werror=unused-variable
+LOCAL_MODULE := net_test_btcore
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_STATIC_LIBRARIES := libbtcore-host libosi-host
+include $(BUILD_HOST_NATIVE_TEST)
+endif
--- /dev/null
+#
+# 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.
+#
+
+static_library("btcore") {
+ sources = [
+ "src/bdaddr.c",
+ "src/counter.c",
+ "src/device_class.c",
+ "src/hal_util.c",
+ "src/module.c",
+ "src/property.c",
+ "src/uuid.c",
+ ]
+
+ include_dirs = [
+ "include",
+ "//osi/include",
+ "//",
+ ]
+}
+
+executable("net_test_btcore") {
+ testonly = true
+ sources = [
+ "test/bdaddr_test.cpp",
+ "test/counter_test.cpp",
+ "test/device_class_test.cpp",
+ "test/property_test.cpp",
+ "test/uuid_test.cpp",
+ "//osi/test/AllocationTestHarness.cpp",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ ]
+
+ deps = [
+ "//btcore",
+ "//osi",
+ "//third_party/gtest:gtest_main",
+ ]
+
+ libs = [ "-lpthread", "-lrt", "-ldl" ]
+}
--- /dev/null
+//
+// 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);
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdatomic.h>
#include <string.h>
#include <sys/eventfd.h>
-#include "osi/include/allocator.h"
-#include "osi/include/atomic.h"
#include "btcore/include/counter.h"
-#include "osi/include/hash_map.h"
-#include "osi/include/list.h"
#include "btcore/include/module.h"
-#include "osi/include/osi.h"
+#include "osi/include/allocator.h"
#include "osi/include/hash_functions.h"
+#include "osi/include/hash_map.h"
+#include "osi/include/list.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/socket.h"
#include "osi/include/thread.h"
typedef int (*handler_t)(socket_t * socket);
typedef struct counter_t {
- atomic_s64_t val;
+ _Atomic(int64_t) val;
} counter_t;
typedef struct hash_element_t {
hash_map_counter_ = hash_map_new(COUNTER_NUM_BUCKETS, hash_function_string,
NULL, hash_element_free_, NULL);
if (hash_map_counter_ == NULL) {
- LOG_ERROR("%s unable to allocate resources", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate resources", __func__);
return future_new_immediate(FUTURE_FAIL);
}
if (!counter_socket_open()) {
- LOG_ERROR("%s unable to open counter port", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to open counter port", __func__);
return future_new_immediate(FUTURE_FAIL);
}
return future_new_immediate(FUTURE_SUCCESS);
return future_new_immediate(FUTURE_SUCCESS);
}
-module_t counter_module = {
+EXPORT_SYMBOL module_t counter_module = {
.name = COUNTER_MODULE,
.init = counter_init,
.start_up = NULL,
assert(name != NULL);
counter_t *counter = name_to_counter_(name);
if (counter)
- atomic_store_s64(&counter->val, val);
+ atomic_store(&counter->val, val);
}
void counter_add(const char *name, counter_data_t val) {
assert(name != NULL);
counter_t *counter = name_to_counter_(name);
if (counter) {
- if (val == 1)
- atomic_inc_prefix_s64(&counter->val);
- else
- atomic_add_s64(&counter->val, val);
+ atomic_fetch_add(&counter->val, val);
}
}
if (!counter) {
return NULL;
}
- atomic_store_s64(&counter->val, initial_val);
+ atomic_store(&counter->val, initial_val);
return counter;
}
counter = counter_new_(0);
if (!counter) {
- LOG_ERROR("%s unable to create new counter name:%s", __func__, name);
+ LOG_ERROR(LOG_TAG, "%s unable to create new counter name:%s", __func__, name);
goto exit;
}
hash_element_t *element = hash_element_new_();
if (!element) {
- LOG_ERROR("%s unable to create counter element name:%s", __func__, name);
+ LOG_ERROR(LOG_TAG, "%s unable to create counter element name:%s", __func__, name);
counter_free_(counter);
counter = NULL;
goto exit;
element->key = name;
element->val = counter;
if (!hash_map_set(hash_map_counter_, name, counter)) {
- LOG_ERROR("%s unable to set new counter into hash map name:%s", __func__, name);
+ LOG_ERROR(LOG_TAG, "%s unable to set new counter into hash map name:%s", __func__, name);
hash_element_free_(element);
counter_free_(counter);
counter = NULL;
clients_ = list_new(client_free);
if (!clients_) {
- LOG_ERROR("%s unable to create counter clients list", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create counter clients list", __func__);
goto error;
}
thread_ = thread_new("counter_socket");
if (!thread_) {
- LOG_ERROR("%s unable to create counter thread", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create counter thread", __func__);
goto error;
}
listen_socket_ = socket_new();
if (!listen_socket_) {
- LOG_ERROR("%s unable to create listen socket", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create listen socket", __func__);
goto error;
}
if (!socket_listen(listen_socket_, LISTEN_PORT)) {
- LOG_ERROR("%s unable to setup listen socket", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to setup listen socket", __func__);
goto error;
}
- LOG_INFO("%s opened counter server socket", __func__);
+ LOG_INFO(LOG_TAG, "%s opened counter server socket", __func__);
socket_register(listen_socket_, thread_get_reactor(thread_), NULL, accept_ready, NULL);
return true;
thread_ = NULL;
clients_ = NULL;
- LOG_INFO("%s closed counter server socket", __func__);
+ LOG_INFO(LOG_TAG, "%s closed counter server socket", __func__);
}
static bool monitor_counter_iter_cb(const char *name, counter_data_t val, void *context) {
assert(socket != NULL);
assert(socket == listen_socket_);
- LOG_INFO("%s accepted OSI monitor socket", __func__);
+ LOG_INFO(LOG_TAG, "%s accepted OSI monitor socket", __func__);
socket = socket_accept(socket);
if (!socket)
return;
client_t *client = (client_t *)osi_calloc(sizeof(client_t));
if (!client) {
- LOG_ERROR("%s unable to allocate memory for client", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for client", __func__);
socket_free(socket);
return;
}
client->socket = socket;
if (!list_append(clients_, client)) {
- LOG_ERROR("%s unable to add client to list", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to add client to list", __func__);
client_free(client);
return;
}
--- /dev/null
+//
+// 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)
+}
#include <pthread.h>
#include <string.h>
-#include "osi/include/allocator.h"
-#include "osi/include/hash_map.h"
#include "btcore/include/module.h"
-#include "osi/include/osi.h"
+#include "osi/include/allocator.h"
#include "osi/include/hash_functions.h"
+#include "osi/include/hash_map.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
typedef enum {
MODULE_STATE_NONE = 0,
assert(get_module_state(module) == MODULE_STATE_NONE);
if (!call_lifecycle_function(module->init)) {
- LOG_ERROR("%s failed to initialize \"%s\"", __func__, module->name);
+ LOG_ERROR(LOG_TAG, "%s failed to initialize \"%s\"", __func__, module->name);
return false;
}
assert(get_module_state(module) == MODULE_STATE_INITIALIZED || module->init == NULL);
if (!call_lifecycle_function(module->start_up)) {
- LOG_ERROR("%s failed to start up \"%s\"", __func__, module->name);
+ LOG_ERROR(LOG_TAG, "%s failed to start up \"%s\"", __func__, module->name);
return false;
}
return;
if (!call_lifecycle_function(module->shut_down))
- LOG_ERROR("%s found \"%s\" reported failure during shutdown. Continuing anyway.", __func__, module->name);
+ LOG_ERROR(LOG_TAG, "%s found \"%s\" reported failure during shutdown. Continuing anyway.", __func__, module->name);
set_module_state(module, MODULE_STATE_INITIALIZED);
}
return;
if (!call_lifecycle_function(module->clean_up))
- LOG_ERROR("%s found \"%s\" reported failure during cleanup. Continuing anyway.", __func__, module->name);
+ LOG_ERROR(LOG_TAG, "%s found \"%s\" reported failure during cleanup. Continuing anyway.", __func__, module->name);
set_module_state(module, MODULE_STATE_NONE);
}
--- /dev/null
+#
+# 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.
+#
+
+static_library("btif") {
+ sources = [
+ "src/btif_av.c",
+ "src/btif_config.c",
+ "src/btif_config_transcode.cpp",
+ "src/btif_core.c",
+ "src/btif_debug.c",
+ "src/btif_debug_btsnoop.c",
+ "src/btif_debug_conn.c",
+ "src/btif_dm.c",
+ "src/btif_gatt.c",
+ "src/btif_gatt_client.c",
+ "src/btif_gatt_multi_adv_util.c",
+ "src/btif_gatt_server.c",
+ "src/btif_gatt_test.c",
+ "src/btif_gatt_util.c",
+ "src/btif_hf.c",
+ "src/btif_hf_client.c",
+ "src/btif_hh.c",
+ "src/btif_hl.c",
+ "src/btif_mce.c",
+ "src/btif_media_task.c",
+ "src/btif_pan.c",
+ "src/btif_profile_queue.c",
+ "src/btif_rc.c",
+ "src/btif_sdp.c",
+ "src/btif_sdp_server.c",
+ "src/btif_sm.c",
+ "src/btif_sock.c",
+ "src/btif_sock_l2cap.c",
+ "src/btif_sock_rfc.c",
+ "src/btif_sock_sco.c",
+ "src/btif_sock_sdp.c",
+ "src/btif_sock_thread.c",
+ "src/btif_sock_util.c",
+ "src/btif_storage.c",
+ "src/btif_util.c",
+ "src/stack_manager.c",
+ ]
+
+ # BTIF callouts
+ sources += [
+ "co/bta_ag_co.c",
+ "co/bta_dm_co.c",
+ "co/bta_av_co.c",
+ "co/bta_hh_co.c",
+ "co/bta_hl_co.c",
+ "co/bta_pan_co.c",
+ "co/bta_gattc_co.c",
+ "co/bta_gatts_co.c",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//audio_a2dp_hw",
+ "//bta/include",
+ "//bta/sys",
+ "//btcore/include",
+ "//embdrv/sbc/encoder/include",
+ "//gki/common",
+ "//hci/include",
+ "//osi/include",
+ "//stack/a2dp",
+ "//stack/btm",
+ "//stack/include",
+ "//third_party/tinyxml2",
+ "//include",
+ "//udrv/include",
+ "//utils/include",
+ "//vnd/include",
+ ]
+}
{
UNUSED(app_id);
- unsigned idx = 0;
-
bdstr_t bdstr;
sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x",
remote_bda[0], remote_bda[1], remote_bda[2],
*
******************************************************************************/
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include <string.h>
-#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <sys/un.h>
#include <time.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <cutils/sockets.h>
+
#include "bta_api.h"
-#include "btm_api.h"
-#include "bta_sys.h"
#include "bta_hl_api.h"
-#include "bta_hl_co.h"
#include "bta_hl_ci.h"
+#include "bta_hl_co.h"
+#include "bta_sys.h"
#include "btif_hl.h"
#include "btif_util.h"
-
+#include "btm_api.h"
/*****************************************************************************
** Constants and Data Types
#define BTIF_COMMON_H
#include <stdlib.h>
+
#include <hardware/bluetooth.h>
#include "bt_types.h"
#include "bta_api.h"
#include "osi.h"
-
-#ifndef LOG_TAG
-#error "LOG_TAG not defined, please add in .c file prior to including bt_common.h"
-#endif
-
#include "osi/include/log.h"
/*******************************************************************************
** Constants & Macros
********************************************************************************/
-#define ASSERTC(cond, msg, val) if (!(cond)) { LOG_ERROR( \
+#define ASSERTC(cond, msg, val) if (!(cond)) { LOG_ERROR(LOG_TAG, \
"### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
/* Calculate start of event enumeration; id is top 8 bits of event */
*
******************************************************************************/
-
-#ifndef BTIF_GATT_MULTI_ADV_UTIL_H
-#define BTIF_GATT_MULTI_ADV_UTIL_H
+#pragma once
#include <hardware/bluetooth.h>
+
#include "bta_api.h"
#define CLNT_IF_IDX 0
uint8_t* p_service_uuid;
} btif_adv_data_t;
+
typedef struct
{
- BOOLEAN is_scan_rsp;
UINT8 client_if;
- UINT16 service_uuid_len;
tBTA_BLE_AD_MASK mask;
tBTA_BLE_ADV_DATA data;
tBTA_BLE_ADV_PARAMS param;
TIMER_LIST_ENT tle_limited_timer;
int timeout_s;
-}btgatt_multi_adv_inst_cb;
+} btgatt_multi_adv_inst_cb;
typedef struct
{
- INT8 *clntif_map;
+ INT8 *clntif_map;
// Includes the stored data for standard LE instance
btgatt_multi_adv_inst_cb *inst_cb;
} btgatt_multi_adv_common_data;
extern btgatt_multi_adv_common_data *btif_obtain_multi_adv_data_cb();
+
extern void btif_gattc_incr_app_count(void);
extern void btif_gattc_decr_app_count(void);
extern int btif_multi_adv_add_instid_map(int client_if, int inst_id,
char* service_uuid, btif_adv_data_t *p_multi_adv_inst);
extern void btif_gattc_adv_data_cleanup(const btif_adv_data_t* adv);
void btif_multi_adv_timer_ctrl(int client_if, TIMER_CBACK cb);
-#endif
-
*
******************************************************************************/
-
#ifndef BTIF_GATT_UTIL_H
#define BTIF_GATT_UTIL_H
-#include "bta_api.h"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "bta/include/bta_gatt_api.h"
void btif_to_bta_uuid(tBT_UUID *p_dest, bt_uuid_t *p_src);
void btif_to_bta_gatt_id(tBTA_GATT_ID *p_dest, btgatt_gatt_id_t *p_src);
#ifndef BTIF_HL_H
#define BTIF_HL_H
+#include <hardware/bluetooth.h>
+
+#include "bta_hl_api.h"
+#include "gki.h"
+
/*******************************************************************************
** Constants & Macros
********************************************************************************/
#define BTIF_HL_CCH_NUM_FILTER_ELEMS 3
#define BTIF_HL_APPLICATION_NAME_LEN 512
-
-
/*******************************************************************************
** Type definitions and return values
********************************************************************************/
int fd;
} btif_hl_send_chan_state_cb_t;
-
typedef struct
{
UINT8 app_idx;
btif_hl_update_mdl_t update_mdl;
} btif_hl_evt_cb_t;
-
/*******************************************************************************
** Functions
********************************************************************************/
#ifndef BTIF_PROFILE_QUEUE_H
#define BTIF_PROFILE_QUEUE_H
+#include <hardware/bluetooth.h>
+
typedef bt_status_t (*btif_connect_cb_t) (bt_bdaddr_t *bda, uint16_t uuid);
bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t *bda, btif_connect_cb_t connect_cb);
#ifndef BTIF_SM_H
#define BTIF_SM_H
+#include <hardware/bluetooth.h>
+
+#include "stack/include/bt_types.h"
+
/*****************************************************************************
** Constants & Macros
******************************************************************************/
#define BTIF_SM_ENTER_EVT 0xFFFF
#define BTIF_SM_EXIT_EVT 0xFFFE
-
/*****************************************************************************
** Type definitions and return values
******************************************************************************/
typedef void* btif_sm_handle_t;
typedef BOOLEAN(*btif_sm_handler_t)(btif_sm_event_t event, void *data);
-
/*****************************************************************************
** Functions
**
#ifndef BTIF_SOCK_L2CAP_H
#define BTIF_SOCK_L2CAP_H
-
+#include <hardware/bluetooth.h>
#define L2CAP_MASK_FIXED_CHANNEL 0x10000
-
bt_status_t btsock_l2cap_init(int handle);
bt_status_t btsock_l2cap_cleanup();
bt_status_t btsock_l2cap_listen(const char* name, int channel,
#define BTIF_SOCK_SDP_H
#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
#define BTIF_SOCK_THREAD_H
#include <stdbool.h>
+
+#include <hardware/bluetooth.h>
#include <hardware/bt_sock.h>
/*******************************************************************************
#ifndef BTIF_SOCK_UTIL_H
#define BTIF_SOCK_UTIL_H
-#include "osi/include/log.h"
+#include <stdint.h>
void dump_bin(const char* title, const char* data, int size);
#ifndef BTIF_STORAGE_H
#define BTIF_STORAGE_H
+#include <hardware/bluetooth.h>
+
+#include "bt_target.h"
#include "bt_types.h"
/*******************************************************************************
#pragma once
#include "future.h"
+#include <stdbool.h>
typedef struct {
void (*init_stack)(void);
*
***********************************************************************************/
+#define LOG_NDDEBUG 0
+#define LOG_TAG "bt_bluedroid"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <hardware/bluetooth.h>
+#include <hardware/bt_av.h>
+#include <hardware/bt_gatt.h>
#include <hardware/bt_hf.h>
#include <hardware/bt_hf_client.h>
-#include <hardware/bt_av.h>
-#include <hardware/bt_sock.h>
#include <hardware/bt_hh.h>
#include <hardware/bt_hl.h>
-#include <hardware/bt_pan.h>
#include <hardware/bt_mce.h>
-#include <hardware/bt_gatt.h>
+#include <hardware/bt_pan.h>
#include <hardware/bt_rc.h>
#include <hardware/bt_sdp.h>
+#include <hardware/bt_sock.h>
-#define LOG_NDDEBUG 0
-#define LOG_TAG "bt_bluedroid"
-
+#include "bt_utils.h"
#include "btif_api.h"
#include "btif_debug.h"
#include "btsnoop.h"
#include "btsnoop_mem.h"
-#include "bt_utils.h"
-#include "osi/include/osi.h"
#include "osi/include/allocation_tracker.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "stack_manager.h"
#include "btif_config.h"
*****************************************************************************/
static int init(bt_callbacks_t *callbacks) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
if (interface_ready())
return BT_STATUS_DONE;
}
static int enable(void) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
if (!interface_ready())
return BT_STATUS_NOT_READY;
static const void* get_profile_interface (const char *profile_id)
{
- LOG_INFO("get_profile_interface %s", profile_id);
+ LOG_INFO(LOG_TAG, "get_profile_interface %s", profile_id);
/* sanity check */
if (interface_ready() == FALSE)
int dut_mode_configure(uint8_t enable)
{
- LOG_INFO("dut_mode_configure");
+ LOG_INFO(LOG_TAG, "dut_mode_configure");
/* sanity check */
if (interface_ready() == FALSE)
int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len)
{
- LOG_INFO("dut_mode_send");
+ LOG_INFO(LOG_TAG, "dut_mode_send");
/* sanity check */
if (interface_ready() == FALSE)
#if BLE_INCLUDED == TRUE
int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len)
{
- LOG_INFO("le_test_mode");
+ LOG_INFO(LOG_TAG, "le_test_mode");
/* sanity check */
if (interface_ready() == FALSE)
int config_hci_snoop_log(uint8_t enable)
{
- LOG_INFO("config_hci_snoop_log");
+ LOG_INFO(LOG_TAG, "config_hci_snoop_log");
if (!interface_ready())
return BT_STATUS_NOT_READY;
return 0;
}
-
static struct hw_module_methods_t bt_stack_module_methods = {
.open = open_bluetooth_stack,
};
-struct hw_module_t HAL_MODULE_INFO_SYM = {
+EXPORT_SYMBOL struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
*
******************************************************************************/
-
/*****************************************************************************
*
* Filename: btif_av.c
*
*****************************************************************************/
+#include "btif_av.h"
+
#include <assert.h>
#include <string.h>
-#include <hardware/bluetooth.h>
#include <system/audio.h>
-#include "hardware/bt_av.h"
-#include "osi/include/allocator.h"
-
-#define LOG_TAG "bt_btif_av"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_av.h>
-#include "btif_av.h"
-#include "btif_util.h"
-#include "btif_profile_queue.h"
+#include "bt_utils.h"
#include "bta_api.h"
#include "btif_media.h"
-#include "bta_av_api.h"
-#include "gki.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
#include "btu.h"
-#include "bt_utils.h"
+#include "gki.h"
+#include "osi/include/allocator.h"
/*****************************************************************************
** Constants & Macros
BTIF_TRACE_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV");
memset(&tle_av_open_on_rc, 0, sizeof(tle_av_open_on_rc));
- tle_av_open_on_rc.param = (UINT32)btif_initiate_av_open_tmr_hdlr;
+ tle_av_open_on_rc.param = btif_initiate_av_open_tmr_hdlr;
btu_start_timer(&tle_av_open_on_rc, BTU_TTYPE_USER_FUNC,
BTIF_TIMEOUT_AV_OPEN_ON_RC_SECS);
btif_rc_handler(event, p_data);
return TRUE;
}
-
/*****************************************************************************
**
** Function btif_av_state_closing_handler
return TRUE;
}
-
/*****************************************************************************
**
** Function btif_av_state_opened_handler
#define LOG_TAG "bt_btif_config"
+#include "btif_config.h"
+
#include <assert.h>
#include <ctype.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
-#include "osi/include/alarm.h"
-#include "osi/include/allocator.h"
+#include "bt_types.h"
#include "btcore/include/bdaddr.h"
-#include "btif_config.h"
+#include "btcore/include/module.h"
#include "btif_config_transcode.h"
#include "btif_util.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocator.h"
#include "osi/include/compat.h"
#include "osi/include/config.h"
-#include "btcore/include/module.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
-#include "bt_types.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;
if (!btif_config_get_int(bd_addr_str, "DevType", p_device_type))
return FALSE;
- LOG_DEBUG("%s: Device [%s] type %d", __FUNCTION__, bd_addr_str, *p_device_type);
+ LOG_DEBUG(LOG_TAG, "%s: Device [%s] type %d", __FUNCTION__, bd_addr_str, *p_device_type);
return TRUE;
}
if (!btif_config_get_int(bd_addr_str, "AddrType", p_addr_type))
return FALSE;
- LOG_DEBUG("%s: Device [%s] address type %d", __FUNCTION__, bd_addr_str, *p_addr_type);
+ LOG_DEBUG(LOG_TAG, "%s: Device [%s] address type %d", __FUNCTION__, bd_addr_str, *p_addr_type);
return TRUE;
}
pthread_mutex_init(&lock, NULL);
config = config_new(CONFIG_FILE_PATH);
if (!config) {
- LOG_WARN("%s unable to load config file; attempting to transcode legacy file.", __func__);
+ LOG_WARN(LOG_TAG, "%s unable to load config file; attempting to transcode legacy file.", __func__);
config = btif_config_transcode(LEGACY_CONFIG_FILE_PATH);
if (!config) {
- LOG_WARN("%s unable to transcode legacy file, starting unconfigured.", __func__);
+ LOG_WARN(LOG_TAG, "%s unable to transcode legacy file, starting unconfigured.", __func__);
config = config_new_empty();
if (!config) {
- LOG_ERROR("%s unable to allocate a config object.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__);
goto error;
}
}
// write back to disk.
alarm_timer = alarm_new();
if (!alarm_timer) {
- LOG_ERROR("%s unable to create alarm.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create alarm.", __func__);
goto error;
}
return future_new_immediate(FUTURE_SUCCESS);
}
-const module_t btif_config_module = {
+EXPORT_SYMBOL const module_t btif_config_module = {
.name = BTIF_CONFIG_MODULE,
.init = init,
.start_up = NULL,
XMLDocument document;
int error = document.LoadFile(xml_filename);
if (error != XML_SUCCESS) {
- LOG_ERROR("%s unable to load XML file '%s': %d", __func__, xml_filename, error);
+ LOG_ERROR(LOG_TAG, "%s unable to load XML file '%s': %d", __func__, xml_filename, error);
return NULL;
}
XMLElement *rootElement = document.RootElement();
if (!rootElement) {
- LOG_ERROR("%s unable to find root element; assuming corrupted config file.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to find root element; assuming corrupted config file.", __func__);
return NULL;
}
config_t *config = config_new_empty();
if (!config) {
- LOG_ERROR("%s unable to allocate config object.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate config object.", __func__);
return NULL;
}
*
***********************************************************************************/
+#define LOG_TAG "bt_btif_core"
+
#include <ctype.h>
-#include <cutils/properties.h>
#include <dirent.h>
#include <fcntl.h>
#include <hardware/bluetooth.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
-
-#define LOG_TAG "bt_btif_core"
-#include "btcore/include/bdaddr.h"
+#include <unistd.h>
+
+/**
+ * TODO(armansito): On OSs other than Android, the sys/properties.h system
+ * does not exist. Remove this conditional include once we have a generic way
+ * to obtain system properties.
+ */
+#if !defined(OS_GENERIC)
+#include <cutils/properties.h>
+#endif /* !defined(OS_GENERIC) */
#include "bdaddr.h"
#include "bt_utils.h"
#include "btif_api.h"
#include "btif_av.h"
#include "btif_config.h"
+#include "btif_config.h"
#include "btif_pan.h"
#include "btif_profile_queue.h"
-#include "btif_config.h"
#include "btif_sock.h"
#include "btif_storage.h"
#include "btif_util.h"
#include "btu.h"
#include "device/include/controller.h"
+#include "gki.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/future.h"
-#include "gki.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
-#include "stack_manager.h"
+#include "osi/include/osi.h"
#include "osi/include/thread.h"
+#include "stack_manager.h"
/************************************************************************************
** Constants & Macros
************************************************************************************/
#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
char val[PROPERTY_VALUE_MAX] = {0};
uint8_t valid_bda = FALSE;
int val_size = 0;
+
+ /**
+ * TODO(armansito): On OSs other than Android, the sys/properties.h system
+ * does not exist. Remove this conditional include once we have a generic way
+ * to obtain system properties.
+ */
+#if !defined(OS_GENERIC)
const uint8_t null_bdaddr[BD_ADDR_LEN] = {0,0,0,0,0,0};
/* Get local bdaddr storage path from property */
if (!valid_bda) {
valid_bda = btif_fetch_property(FACTORY_BT_ADDR_PROPERTY, local_addr);
}
+#endif /* !defined(OS_GENERIC) */
/* Generate new BDA if necessary */
if (!valid_bda)
BTIF_TRACE_DEBUG("No preset BDA. Generating BDA: %s for prop %s",
(char*)bdstr, PERSIST_BDADDR_PROPERTY);
+
+ /**
+ * TODO(armansito): On OSs other than Android, the sys/properties.h system
+ * does not exist. Remove this conditional include once we have a generic way
+ * to obtain system properties.
+ */
+#if !defined(OS_GENERIC)
if (property_set(PERSIST_BDADDR_PROPERTY, (char*)bdstr) < 0)
BTIF_TRACE_ERROR("Failed to set random BDA in prop %s",PERSIST_BDADDR_PROPERTY);
+#endif /* !defined(OS_GENERIC) */
}
//save the bd address to config file
bt_jni_workqueue_thread = thread_new(BT_JNI_WORKQUEUE_NAME);
if (bt_jni_workqueue_thread == NULL) {
- LOG_ERROR("%s Unable to create thread %s", __func__, BT_JNI_WORKQUEUE_NAME);
+ LOG_ERROR(LOG_TAG, "%s Unable to create thread %s", __func__, BT_JNI_WORKQUEUE_NAME);
goto error_exit;
}
local_le_features.version_supported = cmn_vsc_cb.version_supported;
local_le_features.total_trackable_advertisers =
cmn_vsc_cb.total_trackable_advertisers;
-
- local_le_features.extended_scan_support = cmn_vsc_cb.extended_scan_support > 0;
- local_le_features.debug_logging_supported = cmn_vsc_cb.debug_logging_supported > 0;
memcpy(prop.val, &local_le_features, prop.len);
#endif
}
#define LOG_TAG "bt_btif_dm"
+#include "btif_dm.h"
+
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <hardware/bluetooth.h>
+/**
+ * TODO(armansito): cutils/properties.h is only being used to pull-in runtime
+ * settings on Android. Remove this conditional include once we have a generic
+ * way to obtain system properties.
+ */
+#if !defined(OS_GENERIC)
#include <cutils/properties.h>
-#include "gki.h"
-#include "btu.h"
-#include "btcore/include/bdaddr.h"
-#include "bta_api.h"
+#endif /* !defined(OS_GENERIC) */
+
+#include "bdaddr.h"
+#include "bta_gatt_api.h"
#include "btif_api.h"
-#include "btif_util.h"
-#include "btif_dm.h"
-#include "btif_storage.h"
-#include "btif_hh.h"
#include "btif_config.h"
+#include "btif_hh.h"
#include "btif_sdp.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "gki.h"
#include "bta_gatt_api.h"
#include "device/include/interop.h"
#include "include/stack_config.h"
#include "osi/include/log.h"
#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "stack_config.h"
#include "stack/btm/btm_int.h"
/******************************************************************************
#define COD_AV_PORTABLE_AUDIO 0x041C
#define COD_AV_HIFI_AUDIO 0x0428
-
#define BTIF_DM_DEFAULT_INQ_MAX_RESULTS 0
#define BTIF_DM_DEFAULT_INQ_MAX_DURATION 10
#define BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING 2
#endif
} btif_dm_pairing_cb_t;
-
typedef struct
{
UINT8 ir[BT_OCTET16_LEN];
/* This flag will be true if HCI_Inquiry is in progress */
static BOOLEAN btif_dm_inquiry_in_progress = FALSE;
-
-
/************************************************************************************
** Static variables
************************************************************************************/
extern int btif_hh_connect(bt_bdaddr_t *bd_addr);
extern void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16);
-
/******************************************************************************
** Functions
******************************************************************************/
sizeof(uint32_t), &remote_cod);
if (btif_storage_get_remote_device_property((bt_bdaddr_t *)remote_bdaddr, &prop_name) == BT_STATUS_SUCCESS)
{
- LOG_INFO("%s remote_cod = 0x%08x cod = 0x%08x", __func__, remote_cod, cod);
+ LOG_INFO(LOG_TAG, "%s remote_cod = 0x%08x cod = 0x%08x", __func__, remote_cod, cod);
if ((remote_cod & 0x7ff) == cod)
return TRUE;
}
bt_property_t prop_name;
bt_remote_version_t info;
-
if (remote_bdaddr == NULL)
return FALSE;
BTM_ReadRemoteVersion(*(BD_ADDR*)remote_bdaddr, &lmp_ver,
&manufacturer, &lmp_subver);
-
-
/* if not available yet, try fetching from config database */
BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_REMOTE_VERSION_INFO,
sizeof(bt_remote_version_t), &info);
return FALSE;
}
-
static void bond_state_changed(bt_status_t status, bt_bdaddr_t *bd_addr, bt_bond_state_t state)
{
// Send bonding state only once - based on outgoing/incoming we may receive duplicates
btm_status = BTM_ReadRemoteVersion(*(BD_ADDR*)p_bd, &lmp_ver,
&mfct_set, &lmp_subver);
- LOG_DEBUG("remote version info [%s]: %x, %x, %x", bdaddr_to_string(p_bd, bdstr, sizeof(bdstr)),
+ LOG_DEBUG(LOG_TAG, "remote version info [%s]: %x, %x, %x", bdaddr_to_string(p_bd, bdstr, sizeof(bdstr)),
lmp_ver, mfct_set, lmp_subver);
if (btm_status == BTM_SUCCESS)
}
}
-
static void btif_update_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
DEV_CLASS dev_class, tBT_DEVICE_TYPE device_type)
{
cod = devclass2uint(p_ssp_cfm_req->dev_class);
if (cod == 0) {
- LOG_DEBUG("%s cod is 0, set as unclassified", __func__);
+ LOG_DEBUG(LOG_TAG, "%s cod is 0, set as unclassified", __func__);
cod = COD_UNCLASSIFIED;
}
cod = devclass2uint(p_ssp_key_notif->dev_class);
if (cod == 0) {
- LOG_DEBUG("%s cod is 0, set as unclassified", __func__);
+ LOG_DEBUG(LOG_TAG, "%s cod is 0, set as unclassified", __func__);
cod = COD_UNCLASSIFIED;
}
if (check_sdp_bl(&bd_addr) && check_cod_hid(&bd_addr, COD_HID_MAJOR))
{
- LOG_WARN("%s:skip SDP", __FUNCTION__);
+ LOG_WARN(LOG_TAG, "%s:skip SDP", __FUNCTION__);
skip_sdp = TRUE;
}
if(!pairing_cb.is_local_initiated && skip_sdp)
{
bond_state_changed(status, &bd_addr, state);
- LOG_WARN("%s: Incoming HID Connection",__FUNCTION__);
+ LOG_WARN(LOG_TAG, "%s: Incoming HID Connection",__FUNCTION__);
bt_property_t prop;
bt_bdaddr_t bd_addr;
bt_uuid_t uuid;
cod = devclass2uint (p_search_data->inq_res.dev_class);
if (cod == 0) {
- LOG_DEBUG("%s cod is 0, set as unclassified", __func__);
+ LOG_DEBUG(LOG_TAG, "%s cod is 0, set as unclassified", __func__);
cod = COD_UNCLASSIFIED;
}
/* TODO: Get the service list and check to see which uuids we got and send it back to the client. */
}
-
{
bt_property_t properties[5];
bt_device_type_t dev_type;
{
char temp[256];
uuid_to_string_legacy((bt_uuid_t*)(p_data->disc_res.p_uuid_list + (i*MAX_UUID_SIZE)), temp);
- LOG_INFO("%s index:%d uuid:%s", __func__, i, temp);
+ LOG_INFO(LOG_TAG, "%s index:%d uuid:%s", __func__, i, temp);
}
}
}
uuid_to_string_legacy(&uuid, temp);
- LOG_INFO("%s uuid:%s", __func__, temp);
+ LOG_INFO(LOG_TAG, "%s uuid:%s", __func__, temp);
bdcpy(bd_addr.address, p_data->disc_ble_res.bd_addr);
prop.type = BT_PROPERTY_UUIDS;
UNUSED (p_io_cap);
UNUSED (p_oob_data);
-
BTIF_TRACE_DEBUG("+%s: p_auth_req=%d", __FUNCTION__, *p_auth_req);
if(pairing_cb.is_local_initiated)
{
#ifdef BTIF_DM_OOB_TEST
void btif_dm_load_local_oob(void)
{
+ /**
+ * TODO(armansito): On OSs other than Android, the sys/properties.h system
+ * does not exist. Remove this conditional include once we have a generic way
+ * to obtain system properties.
+ */
+#if !defined(OS_GENERIC)
char prop_oob[PROPERTY_VALUE_MAX];
property_get("service.brcm.bt.oob", prop_oob, "3");
BTIF_TRACE_DEBUG("btif_dm_load_local_oob prop_oob = %s",prop_oob);
BTIF_TRACE_DEBUG("btif_dm_load_local_oob: read OOB, call BTA_DmLocalOob()");
BTA_DmLocalOob();
}
-#else
+#else /* (BTM_OOB_INCLUDED != TRUE) */
BTIF_TRACE_ERROR("BTM_OOB_INCLUDED is FALSE!!(btif_dm_load_local_oob)");
-#endif
+#endif /* (BTM_OOB_INCLUDED == TRUE) */
}
+#endif /* !defined(OS_GENERIC) */
}
void btif_dm_proc_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r)
{
+ /**
+ * TODO(armansito): On OSs other than Android, the sys/properties.h system
+ * does not exist. Remove this conditional include once we have a generic way
+ * to obtain system properties.
+ */
+#if !defined(OS_GENERIC)
FILE *fp;
char *path_a = "/data/misc/bluedroid/LOCAL/a.key";
char *path_b = "/data/misc/bluedroid/LOCAL/b.key";
}
}
}
+#endif /* !defined(OS_GENERIC) */
}
+
BOOLEAN btif_dm_proc_rmt_oob(BD_ADDR bd_addr, BT_OCTET16 p_c, BT_OCTET16 p_r)
{
+ /**
+ * TODO(armansito): On OSs other than Android, the sys/properties.h system
+ * does not exist. Remove this conditional include once we have a generic way
+ * to obtain system properties.
+ */
+#if !defined(OS_GENERIC)
char t[128];
FILE *fp;
char *path_a = "/data/misc/bluedroid/LOCAL/a.key";
}
BTIF_TRACE_DEBUG("btif_dm_proc_rmt_oob result=%d",result);
return result;
+#else /* defined(OS_GENERIC) */
+ return FALSE;
+#endif /* !defined(OS_GENERIC) */
}
#endif /* BTIF_DM_OOB_TEST */
#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
bond_state_changed(status, &bd_addr, state);
}
-
-
void btif_dm_load_ble_local_keys(void)
{
memset(&ble_local_key_cb, 0, sizeof(btif_dm_local_key_cb_t));
sizeof(tBTM_LE_PID_KEYS));
}
-
if (pairing_cb.ble.is_pcsrk_key_rcvd)
{
btif_storage_add_ble_bonding_key(&bd_addr,
sizeof(tBTM_LE_PCSRK_KEYS));
}
-
if (pairing_cb.ble.is_lenc_key_rcvd)
{
btif_storage_add_ble_bonding_key(&bd_addr,
}
-
void btif_dm_remove_ble_bonding_keys(void)
{
bt_bdaddr_t bd_addr;
btif_storage_remove_ble_bonding_keys(&bd_addr);
}
-
/*******************************************************************************
**
** Function btif_dm_ble_sec_req_evt
BT_SSP_VARIANT_CONSENT, 0);
}
-
-
/*******************************************************************************
**
** Function btif_dm_ble_passkey_req_evt
}
static char* btif_get_default_local_name() {
+ /**
+ * TODO(armansito): On OSs other than Android, the sys/properties.h system
+ * does not exist. Remove this conditional include once we have a generic way
+ * to obtain system properties.
+ */
+#if !defined(OS_GENERIC)
if (btif_default_local_name[0] == '\0')
{
int max_len = sizeof(btif_default_local_name) - 1;
}
btif_default_local_name[max_len] = '\0';
}
+#endif /* !defined(OS_GENERIC) */
return btif_default_local_name;
}
*
******************************************************************************/
-
/*******************************************************************************
*
* Filename: btif_gatt.c
*
*******************************************************************************/
+#define LOG_TAG "bt_btif_gatt"
+
+#include <errno.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_gatt.h>
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include <string.h>
-#define LOG_TAG "bt_btif_gatt"
-
#include "btif_common.h"
#include "btif_util.h"
#include "bta_api.h"
#include "bta_gatt_api.h"
-#include "btif_storage.h"
-
#include "btif_gatt.h"
#include "btif_gatt_util.h"
+#include "btif_storage.h"
const btgatt_callbacks_t *bt_gatt_callbacks = NULL;
*
******************************************************************************/
-
/*******************************************************************************
*
* Filename: btif_gatt_client.c
*
*******************************************************************************/
+#define LOG_TAG "bt_btif_gattc"
+
+#include <errno.h>
#include <hardware/bluetooth.h>
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include <string.h>
-#define LOG_TAG "bt_btif_gattc"
-
#include "btcore/include/bdaddr.h"
#include "btif_common.h"
#include "btif_util.h"
#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
-#include "btif_gatt_multi_adv_util.h"
#include <hardware/bt_gatt.h>
+
#include "bta_api.h"
#include "bta_gatt_api.h"
-#include "btif_storage.h"
#include "btif_config.h"
-
+#include "btif_dm.h"
#include "btif_gatt.h"
+#include "btif_gatt_multi_adv_util.h"
#include "btif_gatt_util.h"
-#include "btif_dm.h"
#include "btif_storage.h"
-
+#include "btif_storage.h"
#include "osi/include/log.h"
#include "vendor_api.h"
#define CHECK_BTGATT_INIT() if (bt_gatt_callbacks == NULL)\
{\
- LOG_WARN("%s: BTGATT not initialized", __FUNCTION__);\
+ LOG_WARN(LOG_TAG, "%s: BTGATT not initialized", __FUNCTION__);\
return BT_STATUS_NOT_READY;\
} else {\
- LOG_VERBOSE("%s", __FUNCTION__);\
+ LOG_VERBOSE(LOG_TAG, "%s", __FUNCTION__);\
}
#define BLE_RESOLVE_ADDR_MSB 0x40 /* bit7, bit6 is 01 to be resolvable random */
btgatt_batch_reports read_reports;
} btgatt_batch_track_cb_t;
-
typedef tBTA_DM_BLE_PF_FILT_PARAMS btgatt_adv_filt_param_t;
typedef struct
static bt_status_t btif_gattc_multi_adv_disable(int client_if);
static void btif_multi_adv_stop_cb(void *p_tle)
{
- int client_if = ((TIMER_LIST_ENT*)p_tle)->data;
+ int client_if = PTR_TO_INT(((TIMER_LIST_ENT*)p_tle)->data);
btif_gattc_multi_adv_disable(client_if); // Does context switch
}
memcpy(p_dev_cb->remote_dev[i].bd_addr.address, p_bda, BD_ADDR_LEN);
p_dev_cb->addr_type = addr_type;
p_dev_cb->remote_dev[i].in_use = TRUE;
- LOG_VERBOSE("%s device added idx=%d", __FUNCTION__, i );
+ LOG_VERBOSE(LOG_TAG, "%s device added idx=%d", __FUNCTION__, i );
break;
}
}
memcpy(p_dev_cb->remote_dev[i].bd_addr.address, p_bda, BD_ADDR_LEN);
p_dev_cb->addr_type = addr_type;
p_dev_cb->remote_dev[i].in_use = TRUE;
- LOG_VERBOSE("%s device overwrite idx=%d", __FUNCTION__, i );
+ LOG_VERBOSE(LOG_TAG, "%s device overwrite idx=%d", __FUNCTION__, i );
p_dev_cb->next_storage_idx++;
if (p_dev_cb->next_storage_idx >= BTIF_GATT_MAX_OBSERVED_DEV)
p_dev_cb->next_storage_idx = 0;
memcpy(bdname.name, p_eir_remote_name, remote_name_len);
bdname.name[remote_name_len]='\0';
- LOG_DEBUG("%s BLE device name=%s len=%d dev_type=%d", __FUNCTION__, bdname.name,
+ LOG_DEBUG(LOG_TAG, "%s BLE device name=%s len=%d dev_type=%d", __FUNCTION__, bdname.name,
remote_name_len, p_btif_cb->device_type );
btif_dm_update_ble_remote_properties( p_btif_cb->bd_addr.address, bdname.name,
p_btif_cb->device_type);
static void btif_gattc_upstreams_evt(uint16_t event, char* p_param)
{
- LOG_VERBOSE("%s: Event %d", __FUNCTION__, event);
+ LOG_VERBOSE(LOG_TAG, "%s: Event %d", __FUNCTION__, event);
tBTA_GATTC *p_data = (tBTA_GATTC*) p_param;
switch (event)
}
case BTA_GATTC_ACL_EVT:
- LOG_DEBUG("BTA_GATTC_ACL_EVT: status = %d", p_data->status);
+ LOG_DEBUG(LOG_TAG, "BTA_GATTC_ACL_EVT: status = %d", p_data->status);
/* Ignore for now */
break;
}
default:
- LOG_ERROR("%s: Unhandled event (%d)!", __FUNCTION__, event);
+ LOG_ERROR(LOG_TAG, "%s: Unhandled event (%d)!", __FUNCTION__, event);
break;
}
btif_gattc_cb_t* p_cb = (btif_gattc_cb_t*) p_param;
if (!p_cb) return;
- LOG_VERBOSE("%s: Event %d", __FUNCTION__, event);
+ LOG_VERBOSE(LOG_TAG, "%s: Event %d", __FUNCTION__, event);
switch (event)
{
}
default:
- LOG_ERROR("%s: Unknown filter type (%d)!", __FUNCTION__, p_cb->action);
+ LOG_ERROR(LOG_TAG, "%s: Unknown filter type (%d)!", __FUNCTION__, p_cb->action);
break;
}
break;
btif_obtain_multi_adv_data_cb();
BTA_BleCfgAdvInstData(
(UINT8)inst_id,
- p_multi_adv_data_cb->inst_cb[cbindex].is_scan_rsp,
+ p_adv_data->set_scan_rsp,
p_multi_adv_data_cb->inst_cb[cbindex].mask,
&p_multi_adv_data_cb->inst_cb[cbindex].data);
}
}
default:
- LOG_ERROR("%s: Unknown event (%d)!", __FUNCTION__, event);
+ LOG_ERROR(LOG_TAG, "%s: Unknown event (%d)!", __FUNCTION__, event);
break;
}
return btif_gattc_test_command_impl(command, params);
}
-
const btgatt_client_interface_t btgattClientInterface = {
btif_gattc_register_app,
btif_gattc_unregister_app,
*
******************************************************************************/
-
/*******************************************************************************
*
* Filename: btif_gatt_multi_adv_util.c
*
*******************************************************************************/
+#define LOG_TAG "bt_btif_gatt"
+
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+
#include "btu.h"
#include "bt_target.h"
-#define LOG_TAG "bt_btif_gatt"
#if (BLE_INCLUDED == TRUE)
-#include "btif_gatt_multi_adv_util.h"
-#include "btif_common.h"
+#include <hardware/bluetooth.h>
#include <hardware/bt_gatt.h>
+
#include "bta_gatt_api.h"
+#include "btif_common.h"
+#include "btif_gatt_multi_adv_util.h"
#include "btif_gatt_util.h"
/*******************************************************************************
return INVALID_ADV_INST;
}
-
void btif_gattc_adv_data_packager(int client_if, bool set_scan_rsp,
bool include_name, bool include_txpower, int min_interval, int max_interval,
int appearance, int manufacturer_len, char* manufacturer_data,
GKI_freebuf(adv->p_manufacturer_data);
}
-
BOOLEAN btif_gattc_copy_datacb(int cbindex, const btif_adv_data_t *p_adv_data,
BOOLEAN bInstData) {
btgatt_multi_adv_common_data *p_multi_adv_data_cb = btif_obtain_multi_adv_data_cb();
if (NULL == p_multi_adv_data_cb || cbindex < 0)
return false;
- BTIF_TRACE_DEBUG("%s", __FUNCTION__);
- memset(&p_multi_adv_data_cb->inst_cb[cbindex].data, 0, sizeof(tBTA_BLE_ADV_DATA));
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ memset(&p_multi_adv_data_cb->inst_cb[cbindex].data, 0,
+ sizeof(p_multi_adv_data_cb->inst_cb[cbindex].data));
p_multi_adv_data_cb->inst_cb[cbindex].mask = 0;
- p_multi_adv_data_cb->inst_cb[cbindex].is_scan_rsp = p_adv_data->set_scan_rsp ? 1 : 0;
if (!p_adv_data->set_scan_rsp)
{
p_multi_adv_data_cb->inst_cb[cbindex].mask = BTM_BLE_AD_BIT_FLAGS;
p_multi_adv_data_cb->inst_cb[cbindex].data.appearance = p_adv_data->appearance;
}
- if (p_adv_data->manufacturer_len > 0 && p_adv_data->p_manufacturer_data != NULL)
+ if (p_adv_data->manufacturer_len > 0 &&
+ p_adv_data->p_manufacturer_data != NULL &&
+ p_adv_data->manufacturer_len < MAX_SIZE_MANUFACTURER_DATA)
{
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_manu =
- GKI_getbuf(sizeof(tBTA_BLE_MANU));
- if (p_multi_adv_data_cb->inst_cb[cbindex].data.p_manu != NULL)
- {
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_manu->p_val =
- GKI_getbuf(p_adv_data->manufacturer_len);
- if (p_multi_adv_data_cb->inst_cb[cbindex].data.p_manu->p_val != NULL)
- {
- p_multi_adv_data_cb->inst_cb[cbindex].mask |= BTM_BLE_AD_BIT_MANU;
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_manu->len =
- p_adv_data->manufacturer_len;
- memcpy(p_multi_adv_data_cb->inst_cb[cbindex].data.p_manu->p_val,
- p_adv_data->p_manufacturer_data, p_adv_data->manufacturer_len);
- }
- }
+ p_multi_adv_data_cb->inst_cb[cbindex].mask |= BTM_BLE_AD_BIT_MANU;
+ p_multi_adv_data_cb->inst_cb[cbindex].data.manu.len =
+ p_adv_data->manufacturer_len;
+ memcpy(&p_multi_adv_data_cb->inst_cb[cbindex].data.manu.val,
+ p_adv_data->p_manufacturer_data, p_adv_data->manufacturer_len);
}
- tBTA_BLE_PROP_ELEM *p_elem_service_data = NULL;
- if (p_adv_data->service_data_len > 0 && p_adv_data->p_service_data != NULL)
+ if (p_adv_data->service_data_len > 0 &&
+ p_adv_data->p_service_data != NULL &&
+ p_adv_data->service_data_len < MAX_SIZE_PROPRIETARY_ELEMENT)
{
- BTIF_TRACE_DEBUG("%s - In service_data", __FUNCTION__);
- p_elem_service_data = GKI_getbuf(sizeof(tBTA_BLE_PROP_ELEM));
- if (p_elem_service_data != NULL)
- {
- p_elem_service_data->p_val = GKI_getbuf(p_adv_data->service_data_len);
- if (p_elem_service_data->p_val != NULL)
- {
- p_elem_service_data->adv_type = BTM_BLE_AD_TYPE_SERVICE_DATA;
- p_elem_service_data->len = p_adv_data->service_data_len;
- memcpy(p_elem_service_data->p_val, p_adv_data->p_service_data,
- p_adv_data->service_data_len);
- } else {
- GKI_freebuf(p_elem_service_data);
- p_elem_service_data = NULL;
- }
- }
- }
+ BTIF_TRACE_DEBUG("%s - In service_data", __func__);
+ tBTA_BLE_PROPRIETARY *p_prop = &p_multi_adv_data_cb->inst_cb[cbindex].data.proprietary;
+ p_prop->num_elem = 1;
- if (NULL != p_elem_service_data)
- {
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_proprietary =
- GKI_getbuf(sizeof(tBTA_BLE_PROPRIETARY));
- if (NULL != p_multi_adv_data_cb->inst_cb[cbindex].data.p_proprietary)
- {
- tBTA_BLE_PROP_ELEM *p_elem = NULL;
- tBTA_BLE_PROPRIETARY *p_prop = p_multi_adv_data_cb->inst_cb[cbindex].data.p_proprietary;
- p_prop->num_elem = 0;
- p_multi_adv_data_cb->inst_cb[cbindex].mask |= BTM_BLE_AD_BIT_PROPRIETARY;
- p_prop->num_elem = 1;
- p_prop->p_elem = GKI_getbuf(sizeof(tBTA_BLE_PROP_ELEM) * p_prop->num_elem);
- p_elem = p_prop->p_elem;
- if (NULL != p_elem)
- memcpy(p_elem++, p_elem_service_data, sizeof(tBTA_BLE_PROP_ELEM));
- GKI_freebuf(p_elem_service_data);
- }
+ tBTA_BLE_PROP_ELEM *p_elem = &p_prop->elem[0];
+ p_elem->adv_type = BTM_BLE_AD_TYPE_SERVICE_DATA;
+ p_elem->len = p_adv_data->service_data_len;
+ memcpy(p_elem->val, p_adv_data->p_service_data,
+ p_adv_data->service_data_len);
+
+ p_multi_adv_data_cb->inst_cb[cbindex].mask |= BTM_BLE_AD_BIT_PROPRIETARY;
}
if (p_adv_data->service_uuid_len && p_adv_data->p_service_uuid)
{
case (LEN_UUID_16):
{
- if (NULL == p_multi_adv_data_cb->inst_cb[cbindex].data.p_services)
+ if (p_multi_adv_data_cb->inst_cb[cbindex].data.services.num_service == 0)
{
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_services =
- GKI_getbuf(sizeof(tBTA_BLE_SERVICE));
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_services->list_cmpl = FALSE;
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_services->num_service = 0;
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_services->p_uuid =
- GKI_getbuf(p_adv_data->service_uuid_len / LEN_UUID_128 * LEN_UUID_16);
- p_uuid_out16 = p_multi_adv_data_cb->inst_cb[cbindex].data.p_services->p_uuid;
+ p_multi_adv_data_cb->inst_cb[cbindex].data.services.list_cmpl = FALSE;
+ p_uuid_out16 = p_multi_adv_data_cb->inst_cb[cbindex].data.services.uuid;
}
- if (NULL != p_multi_adv_data_cb->inst_cb[cbindex].data.p_services->p_uuid)
+ if (p_multi_adv_data_cb->inst_cb[cbindex].data.services.num_service < MAX_16BIT_SERVICES)
{
- BTIF_TRACE_DEBUG("%s - In 16-UUID_data", __FUNCTION__);
+ BTIF_TRACE_DEBUG("%s - In 16-UUID_data", __func__);
p_multi_adv_data_cb->inst_cb[cbindex].mask |= BTM_BLE_AD_BIT_SERVICE;
- ++p_multi_adv_data_cb->inst_cb[cbindex].data.p_services->num_service;
+ ++p_multi_adv_data_cb->inst_cb[cbindex].data.services.num_service;
*p_uuid_out16++ = bt_uuid.uu.uuid16;
}
break;
case (LEN_UUID_32):
{
- if (NULL == p_multi_adv_data_cb->inst_cb[cbindex].data.p_service_32b)
+ if (p_multi_adv_data_cb->inst_cb[cbindex].data.service_32b.num_service == 0)
{
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_service_32b =
- GKI_getbuf(sizeof(tBTA_BLE_32SERVICE));
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_service_32b->list_cmpl = FALSE;
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_service_32b->num_service = 0;
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_service_32b->p_uuid =
- GKI_getbuf(p_adv_data->service_uuid_len / LEN_UUID_128 * LEN_UUID_32);
- p_uuid_out32 = p_multi_adv_data_cb->inst_cb[cbindex].data.p_service_32b->p_uuid;
+ p_multi_adv_data_cb->inst_cb[cbindex].data.service_32b.list_cmpl = FALSE;
+ p_uuid_out32 = p_multi_adv_data_cb->inst_cb[cbindex].data.service_32b.uuid;
}
- if (NULL != p_multi_adv_data_cb->inst_cb[cbindex].data.p_service_32b->p_uuid)
+ if (p_multi_adv_data_cb->inst_cb[cbindex].data.service_32b.num_service < MAX_32BIT_SERVICES)
{
- BTIF_TRACE_DEBUG("%s - In 32-UUID_data", __FUNCTION__);
+ BTIF_TRACE_DEBUG("%s - In 32-UUID_data", __func__);
p_multi_adv_data_cb->inst_cb[cbindex].mask |= BTM_BLE_AD_BIT_SERVICE_32;
- ++p_multi_adv_data_cb->inst_cb[cbindex].data.p_service_32b->num_service;
+ ++p_multi_adv_data_cb->inst_cb[cbindex].data.service_32b.num_service;
*p_uuid_out32++ = bt_uuid.uu.uuid32;
}
break;
case (LEN_UUID_128):
{
/* Currently, only one 128-bit UUID is supported */
- if (NULL == p_multi_adv_data_cb->inst_cb[cbindex].data.p_services_128b)
+ if (p_multi_adv_data_cb->inst_cb[cbindex].data.services_128b.num_service == 0)
{
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_services_128b =
- GKI_getbuf(sizeof(tBTA_BLE_128SERVICE));
- if (NULL != p_multi_adv_data_cb->inst_cb[cbindex].data.p_services_128b)
- {
- BTIF_TRACE_DEBUG("%s - In 128-UUID_data", __FUNCTION__);
- p_multi_adv_data_cb->inst_cb[cbindex].mask |= BTM_BLE_AD_BIT_SERVICE_128;
- memcpy(p_multi_adv_data_cb->inst_cb[cbindex].data.p_services_128b->uuid128,
- bt_uuid.uu.uuid128, LEN_UUID_128);
- BTIF_TRACE_DEBUG("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", bt_uuid.uu.uuid128[0],
- bt_uuid.uu.uuid128[1],bt_uuid.uu.uuid128[2], bt_uuid.uu.uuid128[3],
- bt_uuid.uu.uuid128[4],bt_uuid.uu.uuid128[5],bt_uuid.uu.uuid128[6],
- bt_uuid.uu.uuid128[7],bt_uuid.uu.uuid128[8],bt_uuid.uu.uuid128[9],
- bt_uuid.uu.uuid128[10],bt_uuid.uu.uuid128[11],bt_uuid.uu.uuid128[12],
- bt_uuid.uu.uuid128[13],bt_uuid.uu.uuid128[14],bt_uuid.uu.uuid128[15]);
- p_multi_adv_data_cb->inst_cb[cbindex].data.p_services_128b->list_cmpl = TRUE;
- }
+ BTIF_TRACE_DEBUG("%s - In 128-UUID_data", __FUNCTION__);
+ p_multi_adv_data_cb->inst_cb[cbindex].mask |=
+ BTM_BLE_AD_BIT_SERVICE_128;
+ memcpy(p_multi_adv_data_cb->inst_cb[cbindex]
+ .data.services_128b.uuid128,
+ bt_uuid.uu.uuid128, LEN_UUID_128);
+ BTIF_TRACE_DEBUG(
+ "%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x",
+ bt_uuid.uu.uuid128[0], bt_uuid.uu.uuid128[1],
+ bt_uuid.uu.uuid128[2], bt_uuid.uu.uuid128[3],
+ bt_uuid.uu.uuid128[4], bt_uuid.uu.uuid128[5],
+ bt_uuid.uu.uuid128[6], bt_uuid.uu.uuid128[7],
+ bt_uuid.uu.uuid128[8], bt_uuid.uu.uuid128[9],
+ bt_uuid.uu.uuid128[10], bt_uuid.uu.uuid128[11],
+ bt_uuid.uu.uuid128[12], bt_uuid.uu.uuid128[13],
+ bt_uuid.uu.uuid128[14], bt_uuid.uu.uuid128[15]);
+ ++p_multi_adv_data_cb->inst_cb[cbindex]
+ .data.services_128b.num_service;
+ p_multi_adv_data_cb->inst_cb[cbindex]
+ .data.services_128b.list_cmpl = TRUE;
}
break;
}
STD_ADV_INSTID : btif_gattc_obtain_idx_for_datacb(inst_id, INST_ID_IDX);
if (cbindex < 0) return;
- BTIF_TRACE_DEBUG("Cleaning up multi_inst_cb for inst_id %d, cbindex %d", inst_id, cbindex);
+ BTIF_TRACE_DEBUG("%s: inst_id %d, cbindex %d", __func__, inst_id, cbindex);
btif_gattc_cleanup_multi_inst_cb(&p_multi_adv_data_cb->inst_cb[cbindex], stop_timer);
}
p_multi_inst_cb->tle_limited_timer.in_use = 0;
}
- // Manufacturer data cleanup
- if (p_multi_inst_cb->data.p_manu != NULL)
- {
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_manu->p_val);
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_manu);
- }
-
- // Proprietary data cleanup
- if (p_multi_inst_cb->data.p_proprietary != NULL)
- {
- int i = 0;
- tBTA_BLE_PROP_ELEM *p_elem = p_multi_inst_cb->data.p_proprietary->p_elem;
- while (i++ != p_multi_inst_cb->data.p_proprietary->num_elem
- && p_elem)
- {
- btif_gattc_cleanup((void**) &p_elem->p_val);
- ++p_elem;
- }
-
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_proprietary->p_elem);
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_proprietary);
- }
-
- // Service list cleanup
- if (p_multi_inst_cb->data.p_services != NULL)
- {
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_services->p_uuid);
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_services);
- }
-
- // Service data cleanup
- if (p_multi_inst_cb->data.p_service_data != NULL)
- {
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_service_data->p_val);
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_service_data);
- }
-
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_services_128b);
-
- if (p_multi_inst_cb->data.p_service_32b != NULL)
- {
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_service_32b->p_uuid);
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_service_32b);
- }
-
- if (p_multi_inst_cb->data.p_sol_services != NULL)
- {
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_sol_services->p_uuid);
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_sol_services);
- }
-
- if (p_multi_inst_cb->data.p_sol_service_32b != NULL)
- {
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_sol_service_32b->p_uuid);
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_sol_service_32b);
- }
-
- btif_gattc_cleanup((void**) &p_multi_inst_cb->data.p_sol_service_128b);
+ memset(&p_multi_inst_cb->data, 0, sizeof(p_multi_inst_cb->data));
}
void btif_gattc_cleanup(void** buf)
btu_stop_timer_oneshot(&p_multi_adv_data_cb->inst_cb[cbindex].tle_limited_timer);
memset(&p_multi_adv_data_cb->inst_cb[cbindex].tle_limited_timer, 0, sizeof(TIMER_LIST_ENT));
- p_multi_adv_data_cb->inst_cb[cbindex].tle_limited_timer.param = (UINT32)cb;
- p_multi_adv_data_cb->inst_cb[cbindex].tle_limited_timer.data = (UINT32)client_if;
+ p_multi_adv_data_cb->inst_cb[cbindex].tle_limited_timer.param = cb;
+ p_multi_adv_data_cb->inst_cb[cbindex].tle_limited_timer.data = INT_TO_PTR(client_if);
btu_start_timer_oneshot(&p_multi_adv_data_cb->inst_cb[cbindex].tle_limited_timer,
BTU_TTYPE_USER_FUNC, p_multi_adv_data_cb->inst_cb[cbindex].timeout_s);
}
*
******************************************************************************/
-
/************************************************************************************
*
* Filename: btif_gatt_server.c
*
***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_gatt.h>
+#define LOG_TAG "bt_btif_gatt"
+
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include <string.h>
-#define LOG_TAG "bt_btif_gatt"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
#include "btif_common.h"
#include "btif_util.h"
#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
-#include "gki.h"
#include "bta_api.h"
#include "bta_gatt_api.h"
-#include "btif_dm.h"
-#include "btif_storage.h"
#include "btif_config.h"
-
+#include "btif_dm.h"
#include "btif_gatt.h"
#include "btif_gatt_util.h"
+#include "btif_storage.h"
+#include "gki.h"
#include "osi/include/log.h"
/************************************************************************************
#define CHECK_BTGATT_INIT() if (bt_gatt_callbacks == NULL)\
{\
- LOG_WARN("%s: BTGATT not initialized", __FUNCTION__);\
+ LOG_WARN(LOG_TAG, "%s: BTGATT not initialized", __FUNCTION__);\
return BT_STATUS_NOT_READY;\
} else {\
- LOG_VERBOSE("%s", __FUNCTION__);\
+ LOG_VERBOSE(LOG_TAG, "%s", __FUNCTION__);\
}
-
typedef enum {
BTIF_GATTS_REGISTER_APP = 2000,
BTIF_GATTS_UNREGISTER_APP,
} __attribute__((packed)) btif_gatts_cb_t;
-
/************************************************************************************
** Static variables
************************************************************************************/
extern const btgatt_callbacks_t *bt_gatt_callbacks;
-
/************************************************************************************
** Static functions
************************************************************************************/
static void btapp_gatts_handle_cback(uint16_t event, char* p_param)
{
- LOG_VERBOSE("%s: Event %d", __FUNCTION__, event);
+ LOG_VERBOSE(LOG_TAG, "%s: Event %d", __FUNCTION__, event);
tBTA_GATTS *p_data = (tBTA_GATTS*)p_param;
switch (event)
case BTA_GATTS_OPEN_EVT:
case BTA_GATTS_CANCEL_OPEN_EVT:
case BTA_GATTS_CLOSE_EVT:
- LOG_DEBUG("%s: Empty event (%d)!", __FUNCTION__, event);
+ LOG_DEBUG(LOG_TAG, "%s: Empty event (%d)!", __FUNCTION__, event);
break;
default:
- LOG_ERROR("%s: Unhandled event (%d)!", __FUNCTION__, event);
+ LOG_ERROR(LOG_TAG, "%s: Unhandled event (%d)!", __FUNCTION__, event);
break;
}
btif_gatts_cb_t* p_cb = (btif_gatts_cb_t*)p_param;
if (!p_cb) return;
- LOG_VERBOSE("%s: Event %d", __FUNCTION__, event);
+ LOG_VERBOSE(LOG_TAG, "%s: Event %d", __FUNCTION__, event);
switch (event)
{
}
default:
- LOG_ERROR("%s: Unknown event (%d)!", __FUNCTION__, event);
+ LOG_ERROR(LOG_TAG, "%s: Unknown event (%d)!", __FUNCTION__, event);
break;
}
}
*
******************************************************************************/
+#define LOG_TAG "bt_btif_gatt"
-#include <hardware/bluetooth.h>
-#include <hardware/bt_gatt.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include <string.h>
-#define LOG_TAG "bt_btif_gatt"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
#include "btif_common.h"
#include "btif_util.h"
#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
-#include "bta_api.h"
#include "bta_gatt_api.h"
-#include "btif_storage.h"
#include "bte_appl.h"
-
+#include "btif_dm.h"
#include "btif_gatt.h"
#include "btif_gatt_util.h"
-#include "btif_dm.h"
-
+#include "btif_storage.h"
#include "gatt_api.h"
#include "osi/include/log.h"
UNUSED(reason);
UNUSED (transport);
- LOG_DEBUG("%s: conn_id=%d, connected=%d", __FUNCTION__, conn_id, connected);
+ LOG_DEBUG(LOG_TAG, "%s: conn_id=%d, connected=%d", __FUNCTION__, conn_id, connected);
test_cb.conn_id = connected ? conn_id : 0;
}
static void btif_test_command_complete_cback(UINT16 conn_id, tGATTC_OPTYPE op,
tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
{
- LOG_DEBUG ("%s: op_code=0x%02x, conn_id=0x%x. status=0x%x",
+ LOG_DEBUG(LOG_TAG, "%s: op_code=0x%02x, conn_id=0x%x. status=0x%x",
__FUNCTION__, op, conn_id, status);
switch (op)
break;
default:
- LOG_DEBUG ("%s: Unknown op_code (0x%02x)", __FUNCTION__, op);
+ LOG_DEBUG(LOG_TAG, "%s: Unknown op_code (0x%02x)", __FUNCTION__, op);
break;
}
}
-
static void btif_test_discovery_result_cback(UINT16 conn_id, tGATT_DISC_TYPE disc_type,
tGATT_DISC_RES *p_data)
{
char str_buf[50];
UNUSED(conn_id);
- LOG_DEBUG("------ GATT Discovery result %-22s -------", disc_name[disc_type]);
- LOG_DEBUG(" Attribute handle: 0x%04x (%d)", p_data->handle, p_data->handle);
+ LOG_DEBUG(LOG_TAG, "------ GATT Discovery result %-22s -------", disc_name[disc_type]);
+ LOG_DEBUG(LOG_TAG, " Attribute handle: 0x%04x (%d)", p_data->handle, p_data->handle);
if (disc_type != GATT_DISC_CHAR_DSCPT) {
- LOG_DEBUG(" Attribute type: %s", format_uuid(p_data->type, str_buf));
+ LOG_DEBUG(LOG_TAG, " Attribute type: %s", format_uuid(p_data->type, str_buf));
}
switch (disc_type)
{
case GATT_DISC_SRVC_ALL:
- LOG_DEBUG(" Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
+ LOG_DEBUG(LOG_TAG, " Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
p_data->handle, p_data->value.group_value.e_handle,
p_data->handle, p_data->value.group_value.e_handle);
- LOG_DEBUG(" Service UUID: %s",
+ LOG_DEBUG(LOG_TAG, " Service UUID: %s",
format_uuid(p_data->value.group_value.service_type, str_buf));
break;
case GATT_DISC_SRVC_BY_UUID:
- LOG_DEBUG(" Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
+ LOG_DEBUG(LOG_TAG, " Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
p_data->handle, p_data->value.handle,
p_data->handle, p_data->value.handle);
break;
case GATT_DISC_INC_SRVC:
- LOG_DEBUG(" Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
+ LOG_DEBUG(LOG_TAG, " Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
p_data->value.incl_service.s_handle, p_data->value.incl_service.e_handle,
p_data->value.incl_service.s_handle, p_data->value.incl_service.e_handle);
- LOG_DEBUG(" Service UUID: %s",
+ LOG_DEBUG(LOG_TAG, " Service UUID: %s",
format_uuid(p_data->value.incl_service.service_type, str_buf));
break;
case GATT_DISC_CHAR:
- LOG_DEBUG(" Properties: 0x%02x",
+ LOG_DEBUG(LOG_TAG, " Properties: 0x%02x",
p_data->value.dclr_value.char_prop);
- LOG_DEBUG(" Characteristic UUID: %s",
+ LOG_DEBUG(LOG_TAG, " Characteristic UUID: %s",
format_uuid(p_data->value.dclr_value.char_uuid, str_buf));
break;
case GATT_DISC_CHAR_DSCPT:
- LOG_DEBUG(" Descriptor UUID: %s", format_uuid(p_data->type, str_buf));
+ LOG_DEBUG(LOG_TAG, " Descriptor UUID: %s", format_uuid(p_data->type, str_buf));
break;
}
- LOG_DEBUG("-----------------------------------------------------------");
+ LOG_DEBUG(LOG_TAG, "-----------------------------------------------------------");
}
static void btif_test_discovery_complete_cback(UINT16 conn_id,
{
UNUSED(conn_id);
UNUSED(disc_type);
- LOG_DEBUG("%s: status=%d", __FUNCTION__, status);
+ LOG_DEBUG(LOG_TAG, "%s: status=%d", __FUNCTION__, status);
}
static tGATT_CBACK btif_test_callbacks =
switch(command) {
case 0x01: /* Enable */
{
- LOG_DEBUG("%s: ENABLE - enable=%d", __FUNCTION__, params->u1);
+ LOG_DEBUG(LOG_TAG, "%s: ENABLE - enable=%d", __FUNCTION__, params->u1);
if (params->u1)
{
tBT_UUID app_uuid = {LEN_UUID_128,{0xAE}};
case 0x02: /* Connect */
{
- LOG_DEBUG("%s: CONNECT - device=%02x:%02x:%02x:%02x:%02x:%02x (dev_type=%d, addr_type=%d)",
+ LOG_DEBUG(LOG_TAG, "%s: CONNECT - device=%02x:%02x:%02x:%02x:%02x:%02x (dev_type=%d, addr_type=%d)",
__FUNCTION__,
params->bda1->address[0], params->bda1->address[1],
params->bda1->address[2], params->bda1->address[3],
if ( !GATT_Connect(test_cb.gatt_if, params->bda1->address, TRUE, BT_TRANSPORT_LE) )
{
- LOG_ERROR("%s: GATT_Connect failed!", __FUNCTION__);
+ LOG_ERROR(LOG_TAG, "%s: GATT_Connect failed!", __FUNCTION__);
}
break;
}
case 0x03: /* Disconnect */
{
- LOG_DEBUG("%s: DISCONNECT - conn_id=%d", __FUNCTION__, test_cb.conn_id);
+ LOG_DEBUG(LOG_TAG, "%s: DISCONNECT - conn_id=%d", __FUNCTION__, test_cb.conn_id);
GATT_Disconnect(test_cb.conn_id);
break;
}
if (params->u1 >= GATT_DISC_MAX)
{
- LOG_ERROR("%s: DISCOVER - Invalid type (%d)!", __FUNCTION__, params->u1);
+ LOG_ERROR(LOG_TAG, "%s: DISCOVER - Invalid type (%d)!", __FUNCTION__, params->u1);
return 0;
}
param.e_handle = params->u3;
btif_to_bta_uuid(¶m.service, params->uuid1);
- LOG_DEBUG("%s: DISCOVER (%s), conn_id=%d, uuid=%s, handles=0x%04x-0x%04x",
+ LOG_DEBUG(LOG_TAG, "%s: DISCOVER (%s), conn_id=%d, uuid=%s, handles=0x%04x-0x%04x",
__FUNCTION__, disc_name[params->u1], test_cb.conn_id,
format_uuid(param.service, buf), params->u2, params->u3);
GATTC_Discover(test_cb.conn_id, params->u1, ¶m);
}
case 0xF0: /* Pairing configuration */
- LOG_DEBUG("%s: Setting pairing config auth=%d, iocaps=%d, keys=%d/%d/%d",
+ LOG_DEBUG(LOG_TAG, "%s: Setting pairing config auth=%d, iocaps=%d, keys=%d/%d/%d",
__FUNCTION__, params->u1, params->u2, params->u3, params->u4,
params->u5);
break;
default:
- LOG_ERROR("%s: UNKNOWN TEST COMMAND 0x%02x", __FUNCTION__, command);
+ LOG_ERROR(LOG_TAG, "%s: UNKNOWN TEST COMMAND 0x%02x", __FUNCTION__, command);
break;
}
return 0;
*
******************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_gatt.h>
+#define LOG_TAG "bt_btif_gatt"
+
+#include "btif_gatt_util.h"
+
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include <string.h>
-#define LOG_TAG "bt_btif_gatt"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
-#include "btcore/include/bdaddr.h"
+#include "bdaddr.h"
#include "bta_api.h"
#include "bta_gatt_api.h"
#include "bta_jv_api.h"
-#include "btif_storage.h"
-#include "btif_config.h"
-
#include "btif_common.h"
+#include "btif_config.h"
#include "btif_dm.h"
-#include "btif_util.h"
#include "btif_gatt.h"
-#include "btif_gatt_util.h"
+#include "btif_storage.h"
+#include "btif_util.h"
#include "gki.h"
#if BTA_GATT_INCLUDED == TRUE
break;
default:
- LOG_ERROR("%s: Unknown UUID length %d!", __FUNCTION__, p_dest->len);
+ LOG_ERROR(LOG_TAG, "%s: Unknown UUID length %d!", __FUNCTION__, p_dest->len);
break;
}
}
break;
default:
- LOG_ERROR("%s: Unknown UUID length %d!", __FUNCTION__, p_src->len);
+ LOG_ERROR(LOG_TAG, "%s: Unknown UUID length %d!", __FUNCTION__, p_src->len);
break;
}
}
-
void bta_to_btif_gatt_id(btgatt_gatt_id_t *p_dest, tBTA_GATT_ID *p_src)
{
p_dest->inst_id = p_src->inst_id;
p_dest->is_primary = p_src->is_primary;
}
-
/*******************************************************************************
* Utility functions
*******************************************************************************/
default:
if (( p_src->status == BTA_GATT_OK ) &&(p_src->p_value != NULL))
{
- LOG_INFO("%s unformat.len = %d ", __FUNCTION__, p_src->p_value->unformat.len);
+ LOG_INFO(LOG_TAG, "%s unformat.len = %d ", __FUNCTION__, p_src->p_value->unformat.len);
p_dest->value.len = p_src->p_value->unformat.len;
if ( p_src->p_value->unformat.len > 0 && p_src->p_value->unformat.p_value != NULL )
{
*
***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_hf.h>
+#define LOG_TAG "bt_btif_hf"
+
#include <stdlib.h>
#include <string.h>
+#include <time.h>
-#define LOG_TAG "bt_btif_hf"
-#include "btif_common.h"
-#include "btif_util.h"
-#include "btif_profile_queue.h"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
-#include "btcore/include/bdaddr.h"
#include "bta_ag_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
/************************************************************************************
** Constants & Macros
static btif_hf_cb_t btif_hf_cb[BTIF_HF_NUM_CB];
-
/************************************************************************************
** Static functions
************************************************************************************/
**
*****************************************************************************/
-
/*******************************************************************************
**
** Function btif_hf_upstreams_evt
ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
}
-
/*******************************************************************************
**
** Function btif_in_hf_generic_evt
}
}
-
/*******************************************************************************
**
** Function btif_hf_init
return BT_STATUS_SUCCESS;
}
-
return BT_STATUS_FAIL;
}
*
***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_hf_client.h>
+#define LOG_TAG "bt_btif_hfc"
+
#include <stdlib.h>
#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf_client.h>
+
+/**
+ * TODO(armansito): On OSs other than Android, the sys/properties.h system
+ * does not exist. Remove this conditional include once we have a generic way
+ * to obtain system properties.
+ */
+#if !defined(OS_GENERIC)
#include <cutils/properties.h>
+#endif /* !defined(OS_GENERIC) */
-#define LOG_TAG "bt_btif_hfc"
-#include "btif_common.h"
-#include "btif_util.h"
-#include "btif_profile_queue.h"
#include "bt_utils.h"
-#include "btcore/include/bdaddr.h"
#include "bta_hf_client_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
/************************************************************************************
** Constants & Macros
** Static variables
************************************************************************************/
static bthf_client_callbacks_t *bt_hf_client_callbacks = NULL;
-char btif_hf_client_version[PROPERTY_VALUE_MAX];
static UINT32 btif_hf_client_features = 0;
+/**
+ * TODO(armansito): On OSs other than Android, the sys/properties.h system
+ * does not exist. Since that is how the HFP version is currently obtained, on
+ * systems other than Android, hardcode 1.5 as the profile version for now,
+ * until there is a generic way to obtain these configuration properties.
+ */
+#if defined(OS_GENERIC)
+const char btif_hf_client_version[] = "1.5";
+#else /* !defined(OS_GENERIC) */
+char btif_hf_client_version[PROPERTY_VALUE_MAX];
+#endif /* defined(OS_GENERIC) */
#define CHECK_BTHF_CLIENT_INIT() if (bt_hf_client_callbacks == NULL)\
{\
static btif_hf_client_cb_t btif_hf_client_cb;
-
/************************************************************************************
** Static functions
************************************************************************************/
{
BTIF_TRACE_EVENT("%s enable:%d", __FUNCTION__, b_enable);
+/**
+ * TODO(armansito): On OSs other than Android, the sys/properties.h system
+ * does not exist. Since that is how the HFP version is currently obtained, on
+ * systems other than Android we're hardcoding the version to 1.5 above.
+ */
+#if !defined(OS_GENERIC)
property_get("ro.bluetooth.hfp.ver", btif_hf_client_version, "1.5");
+#endif /* !defined(OS_GENERIC) */
if (b_enable)
{
*
*
***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_hh.h>
+
+#define LOG_TAG "bt_btif_hh"
+
+#include "btif_hh.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
-
-#define LOG_TAG "bt_btif_hh"
+#include <unistd.h>
#include "bta_api.h"
-#include "bta_hh_api.h"
-#include "btif_storage.h"
-
#include "btif_common.h"
+#include "btif_storage.h"
#include "btif_util.h"
-#include "btif_hh.h"
#include "gki.h"
#include "l2c_api.h"
#include "osi/include/log.h"
#define BTIF_TIMEOUT_VUP_SECS 3
-
#ifndef BTUI_HH_SECURITY
#define BTUI_HH_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
#endif
BTIF_HH_VUP_REQ_EVT
} btif_hh_req_evt_t;
-
/************************************************************************************
** Constants & Macros
************************************************************************************/
#define BTIF_HH_SERVICES (BTA_HID_SERVICE_MASK)
-
-
/************************************************************************************
** Local type definitions
************************************************************************************/
"Logitech MX5500 Keyboard"}
};
-
#define CHECK_BTHH_INIT() if (bt_hh_callbacks == NULL)\
{\
BTIF_TRACE_WARNING("BTHH: %s: BTHH not initialized", __FUNCTION__);\
BTIF_TRACE_EVENT("BTHH: %s", __FUNCTION__);\
}
-
-
/************************************************************************************
** Static functions
************************************************************************************/
//static void hh_update_keyboard_lockstates(btif_hh_device_t *p_dev);
void btif_hh_tmr_hdlr(TIMER_LIST_ENT *tle);
-
/************************************************************************************
** Functions
************************************************************************************/
{
BTIF_TRACE_DEBUG("Start VUP timer ");
memset(&p_dev->vup_timer, 0, sizeof(TIMER_LIST_ENT));
- p_dev->vup_timer.param = (UINT32)btif_hh_tmr_hdlr;
+ p_dev->vup_timer.param = btif_hh_tmr_hdlr;
btu_start_timer(&p_dev->vup_timer, BTU_TTYPE_USER_FUNC,
BTIF_TIMEOUT_VUP_SECS);
}
btif_hh_device_t *p_dev;
btif_hh_added_device_t *p_added_dev;
- LOG_INFO("%s: bda = %02x:%02x:%02x:%02x:%02x:%02x", __FUNCTION__,
+ LOG_INFO(LOG_TAG, "%s: bda = %02x:%02x:%02x:%02x:%02x:%02x", __FUNCTION__,
bd_addr.address[0], bd_addr.address[1], bd_addr.address[2], bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
}
}
-
BOOLEAN btif_hh_copy_hid_info(tBTA_HH_DEV_DSCP_INFO* dest , tBTA_HH_DEV_DSCP_INFO* src)
{
dest->descriptor.dl_len = 0;
return TRUE;
}
-
/*******************************************************************************
**
** Function btif_hh_virtual_unplug
**
*****************************************************************************/
-
/*******************************************************************************
**
** Function btif_hh_upstreams_evt
return;
}
if (p_dev->fd < 0) {
- LOG_ERROR("BTA_HH_GET_DSCP_EVT: Error, failed to find the uhid driver...");
+ LOG_ERROR(LOG_TAG, "BTA_HH_GET_DSCP_EVT: Error, failed to find the uhid driver...");
return;
}
{
p_data->dev_info.bda[3], p_data->dev_info.bda[4], p_data->dev_info.bda[5]);
break;
-
case BTA_HH_VC_UNPLUG_EVT:
BTIF_TRACE_DEBUG("BTA_HH_VC_UNPLUG_EVT: status = %d, handle = %d",
p_data->dev_status.status, p_data->dev_status.handle);
break;
case BTA_HH_API_ERR_EVT :
- LOG_INFO("BTA_HH API_ERR");
+ LOG_INFO(LOG_TAG, "BTA_HH API_ERR");
break;
-
-
default:
BTIF_TRACE_WARNING("%s: Unhandled event: %d", __FUNCTION__, event);
break;
return BT_STATUS_SUCCESS;
}
-
/*******************************************************************************
**
** Function set_info
dscp_info.descriptor.dsc_list = (UINT8 *) GKI_getbuf(dscp_info.descriptor.dl_len);
if (dscp_info.descriptor.dsc_list == NULL)
{
- LOG_ERROR("%s: Failed to allocate DSCP for CB", __FUNCTION__);
+ LOG_ERROR(LOG_TAG, "%s: Failed to allocate DSCP for CB", __FUNCTION__);
return BT_STATUS_FAIL;
}
memcpy(dscp_info.descriptor.dsc_list, &(hid_info.dsc_list), hid_info.dl_len);
BTA_HhSetProtoMode(p_dev->dev_handle, protocolMode);
}
-
return BT_STATUS_SUCCESS;
}
return BT_STATUS_FAIL;
}
-
p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
if (p_dev == NULL) {
BTIF_TRACE_ERROR("%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
BTIF_TRACE_DEBUG("addr = %02X:%02X:%02X:%02X:%02X:%02X",
(*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
-
if (btif_hh_cb.status == BTIF_HH_DISABLED) {
BTIF_TRACE_ERROR("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
return BT_STATUS_FAIL;
memset(hexbuf, 0, len);
//TODO
hex_bytes_filled = ascii_2_hex(report, len, hexbuf);
- LOG_INFO("Hex bytes filled, hex value: %d", hex_bytes_filled);
+ LOG_INFO(LOG_TAG, "Hex bytes filled, hex value: %d", hex_bytes_filled);
if (hex_bytes_filled) {
BT_HDR* p_buf = create_pbuf(hex_bytes_filled, hexbuf);
if (p_buf == NULL) {
}
}
-
/*******************************************************************************
**
** Function cleanup
***********************************************************************************/
#define LOG_TAG "bt_btif_hl"
+#include "btif_hl.h"
+
#include <assert.h>
#include <ctype.h>
-#include <cutils/sockets.h>
#include <errno.h>
#include <fcntl.h>
-#include <hardware/bluetooth.h>
-#include <hardware/bt_hl.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
+#include <sys/prctl.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>
-#include <pthread.h>
-#include <signal.h>
-#include <ctype.h>
-#include <sys/select.h>
-#include <sys/poll.h>
-#include <sys/prctl.h>
-#include <cutils/sockets.h>
-#include <cutils/log.h>
-#include <hardware/bluetooth.h>
#include <hardware/bt_hl.h>
-#include "btif_common.h"
-#include "btif_util.h"
-#include "gki.h"
#include "bta_api.h"
-#include "bta_hl_api.h"
#include "btif_common.h"
-#include "btif_hl.h"
#include "btif_storage.h"
#include "btif_util.h"
#include "btu.h"
-#include "gki.h"
-#include "osi/include/list.h"
#include "mca_api.h"
+#include "osi/include/list.h"
#include "osi/include/log.h"
#define MAX_DATATYPE_SUPPORTED 8
ASSERTC(0, "Callback is NULL", 0); \
}
-
#define BTIF_HL_CALL_CBACK(P_CB, P_CBACK, ...)\
if((p_btif_hl_cb->state != BTIF_HL_STATE_DISABLING) &&\
(p_btif_hl_cb->state != BTIF_HL_STATE_DISABLED)) \
} \
}
-
#define CHECK_BTHL_INIT() if (bt_hl_callbacks == NULL)\
{\
BTIF_TRACE_WARNING("BTHL: %s: BTHL not initialized", __FUNCTION__);\
BTIF_TRACE_EVENT("BTHL: %s", __FUNCTION__);\
}
-
static const btif_hl_data_type_cfg_t data_type_table[] = {
/* Data Specilization Ntx Nrx (from Bluetooth SIG's HDP whitepaper)*/
{BTIF_HL_DATA_TYPE_PULSE_OXIMETER, 9216, 256},
{
BTIF_TRACE_DEBUG("Start CCH timer ");
memset(&p_mcb->cch_timer, 0, sizeof(TIMER_LIST_ENT));
- p_mcb->cch_timer.param = (UINT32)btif_hl_tmr_hdlr;
+ p_mcb->cch_timer.param = btif_hl_tmr_hdlr;
btu_start_timer(&p_mcb->cch_timer, BTU_TTYPE_USER_FUNC,
BTIF_TIMEOUT_CCH_NO_DCH_SECS);
}
memset(p_pcb, 0 , sizeof(btif_hl_pending_chan_cb_t));
}
-
/*******************************************************************************
**
** Function btif_hl_clean_mdl_cb
memset(p_dcb, 0 , sizeof(btif_hl_mdl_cb_t));
}
-
/*******************************************************************************
**
** Function btif_hl_reset_mcb
memset(p_mcb, 0, sizeof(btif_hl_mcl_cb_t));
}
-
/*******************************************************************************
**
** Function btif_hl_find_sdp_idx_using_mdep_filter
tBTA_HL_MDEP_ID peer_mdep_id = p_dch_open_api->peer_mdep_id;
UINT8 mdl_idx;
-
BTIF_TRACE_DEBUG("%s app_idx=%d mcl_idx=%d mdep_cfg_idx=%d",
__FUNCTION__, app_idx, mcl_idx, mdep_cfg_idx );
switch (local_cfg)
return status;
}
-
/*******************************************************************************
**
** Function btif_hl_find_mdl_idx_using_handle
return found;
}
-
/*******************************************************************************
**
** Function btif_hl_find_mdl_idx_using_handle
}
}
-
BTIF_TRACE_EVENT("%s found=%d app_idx=%d mcl_idx=%d mdl_idx=%d ",
__FUNCTION__,found,i,j,k );
return found;
BOOLEAN found = FALSE;
tBTA_HL_MDEP_ROLE peer_mdep_role;
-
BTIF_TRACE_DEBUG("%s app_id=%d local_mdep_role=%d, data_type=%d",
__FUNCTION__, app_id, local_mdep_role, data_type);
bd_addr[2], bd_addr[3],
bd_addr[4], bd_addr[5]);
-
BTIF_TRACE_DEBUG("local_mdep_role=%d", local_mdep_role);
BTIF_TRACE_DEBUG("data_type=%d", data_type);
if (btif_hl_find_app_idx(app_id, &app_idx) )
{
- BTIF_HL_GET_APP_CB_PTR(app_idx);
if (btif_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx))
{
- p_mcb =BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=%d",app_idx, mcl_idx);
BTIF_TRACE_DEBUG("valid_spd_idx=%d sdp_idx=%d",p_mcb->valid_sdp_idx, p_mcb->sdp_idx);
num_mdeps = p_rec->num_mdeps;
BTIF_TRACE_DEBUG("num_mdeps=%d", num_mdeps);
- for (i=0; i< num_mdeps; i++)
+ for (i = 0; i < num_mdeps; i++)
{
BTIF_TRACE_DEBUG("p_rec->mdep_cfg[%d].mdep_role=%d",i, p_rec->mdep_cfg[i].mdep_role);
BTIF_TRACE_DEBUG("p_rec->mdep_cfg[%d].data_type =%d",i, p_rec->mdep_cfg[i].data_type );
return found;
}
-
-
/*******************************************************************************
**
** Function btif_hl_find_mcl_idx
}
}
-
BTIF_TRACE_DEBUG("%s found=%d idx=%d",__FUNCTION__, found, i);
return found;
}
max_tx_apdu_size = BTIF_HL_DEFAULT_SRC_RX_APDU_SIZE;
}
-
}
BTIF_TRACE_DEBUG("%s mdep_role=%d data_type=0x%4x size=%d",
return max_tx_apdu_size;
}
-
/*******************************************************************************
**
** Function btif_hl_get_max_rx_apdu_size
}
}
-
BTIF_TRACE_DEBUG("%s mdep_role=%d data_type=0x%4x size=%d",
__FUNCTION__, mdep_role, data_type, max_rx_apdu_size);
btif_hl_cb.next_channel_id = 1;
}
-
/*******************************************************************************
**
** Function btif_hl_find_app_idx_using_handle
return found;
}
-
/*******************************************************************************
**
** Function btif_hl_proc_dereg_cfm
BTIF_TRACE_DEBUG("%s state %d--->%d",__FUNCTION__, cur_state, state);
}
-
}
/*******************************************************************************
**
return status;
}
-
/*******************************************************************************
**
** Function btif_hl_proc_cch_open_ind
BTIF_TRACE_DEBUG("app_idx=%d", app_idx);
if (btif_hl_find_mcl_idx(app_idx, p_data->cch_open_cfm.bd_addr, &mcl_idx))
{
- BTIF_HL_GET_APP_CB_PTR(app_idx);
-
p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
BTIF_TRACE_DEBUG("mcl_idx=%d, mcl_handle=%d", mcl_idx,p_data->cch_open_cfm.mcl_handle);
p_mcb->mcl_handle = p_data->cch_open_cfm.mcl_handle;
btif_hl_clean_mcb_using_handle(p_data->cch_close_ind.mcl_handle);
}
-
/*******************************************************************************
**
** Function btif_hl_proc_cch_close_cfm
if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_open_ind.mcl_handle, orig_app_idx, &mcl_idx ))
{
- BTIF_HL_GET_APP_CB_PTR(orig_app_idx);
- BTIF_HL_GET_MCL_CB_PTR(orig_app_idx, mcl_idx);
-
if (btif_hl_find_avail_mdl_idx(orig_app_idx, mcl_idx, &mdl_idx))
{
p_dcb = BTIF_HL_GET_MDL_CB_PTR(orig_app_idx, mcl_idx, mdl_idx);
if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_open_cfm.mcl_handle, app_idx, &mcl_idx ))
{
- BTIF_HL_GET_APP_CB_PTR(app_idx);
- BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx))
if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_reconnect_cfm.mcl_handle, app_idx, &mcl_idx ))
{
- BTIF_HL_GET_APP_CB_PTR(app_idx);
- BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx))
p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
BTIF_TRACE_DEBUG("btif_hl_proc_dch_reconnect_ind: app_idx = %d, mcl_idx = %d",
app_idx, mcl_idx);
- BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx))
{
}
}
-
/*******************************************************************************
**
** Function btif_hl_proc_abort_ind
BTIF_TRACE_DEBUG("btif_hl_proc_dch_cong_ind");
-
if (btif_hl_find_mdl_idx_using_handle(p_data->dch_cong_ind.mdl_handle, &app_idx, &mcl_idx, &mdl_idx))
{
p_dcb =BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
BTA_HlRegister(app_id, p_reg_param, btif_hl_cback);
}
-
/*******************************************************************************
**
** Function btif_hl_proc_cb_evt
BOOLEAN send_chan_cb=TRUE;
tBTA_HL_REG_PARAM reg_param;
btif_hl_app_cb_t *p_acb;
- bthl_app_reg_state_t reg_state = BTHL_APP_REG_STATE_REG_FAILED;
- UINT8 preg_idx;
- bt_status_t bt_status;
BTIF_TRACE_DEBUG("%s event %d", __FUNCTION__, event);
btif_hl_display_calling_process_name();
break;
-
case BTA_HL_CCH_OPEN_CFM_EVT:
BTIF_TRACE_DEBUG("Rcv BTA_HL_CCH_OPEN_CFM_EVT");
BTIF_TRACE_DEBUG("app_id=%d,app_handle=%d mcl_handle=%d status =%d",
}
break;
-
case BTA_HL_CCH_OPEN_IND_EVT:
BTIF_TRACE_DEBUG("Rcv BTA_HL_CCH_OPEN_IND_EVT");
BTIF_TRACE_DEBUG("app_handle=%d mcl_handle=%d",
p_data->dch_reconnect_cfm.mdl_id,
p_data->dch_reconnect_cfm.mtu);
-
if (p_data->dch_reconnect_cfm.status == BTA_HL_STATUS_OK)
{
status = btif_hl_proc_dch_reconnect_cfm(p_data);
/* not supported */
break;
-
case BTA_HL_DCH_RECONNECT_IND_EVT:
BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_RECONNECT_IND_EVT");
{
btif_hl_set_state(BTIF_HL_STATE_ENABLED);
-
for (i=0; i < BTA_HL_NUM_APPS ; i ++)
{
p_acb = BTIF_HL_GET_APP_CB_PTR(i);
BTIF_TRACE_EVENT("%s", __FUNCTION__);
btif_hl_display_calling_process_name();
-
for (i=0; i<6; i++)
{
bda[i] = (UINT8) bd_addr->address[i];
BTIF_TRACE_EVENT("%s channel_id=0x%08x", __FUNCTION__, channel_id);
btif_hl_display_calling_process_name();
-
if (btif_hl_if_channel_setup_pending(channel_id, &app_idx, &mcl_idx))
{
btif_hl_dch_abort(app_idx, mcl_idx);
if (btif_hl_find_app_idx(((UINT8)app_id), &app_idx))
{
evt_param.unreg.app_idx = app_idx;
- BTIF_HL_GET_APP_CB_PTR(app_idx);
reg_counter --;
len = sizeof(btif_hl_unreg_t);
status = btif_transfer_context (btif_hl_proc_cb_evt, BTIF_HL_UNREG_APP,
p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
p_acb->in_use = TRUE;
-
p_acb->app_id = btif_hl_get_next_app_id();
if (p_reg_param->application_name != NULL )
if(btif_hl_find_app_idx_using_mdepId(mdep_id,&app_idx))
{
-
- BTIF_HL_GET_APP_CB_PTR(app_idx);
-
p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx);
if (p_mdl)
{
cleanup,
};
-
/*******************************************************************************
**
** Function btif_hl_get_interface
BTIF_TRACE_DEBUG("%s", __FUNCTION__);
soc_queue = list_new(NULL);
if (soc_queue == NULL)
- LOG_ERROR("%s unable to allocate resources for thread", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate resources for thread", __func__);
select_thread_id = create_thread(btif_hl_select_thread, NULL);
}
/*******************************************************************************
*
***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_mce.h>
+#define LOG_TAG "bt_btif_mce"
+
#include <stdlib.h>
#include <string.h>
-#define LOG_TAG "bt_btif_mce"
-#include "btif_common.h"
-#include "btif_util.h"
-#include "btif_profile_queue.h"
-#include "bta_api.h"
-#include "bta_mce_api.h"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_mce.h>
#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_mce_api.h"
#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
/*****************************************************************************
** Static variables
#define LOG_TAG "bt_btif_media"
#include <assert.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <dlfcn.h>
+#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
#include <pthread.h>
#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
#include <sys/time.h>
-#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
-#include "bt_target.h"
-#include "osi/include/fixed_queue.h"
-#include "gki.h"
-#include "bta_api.h"
-#include "btu.h"
-#include "bta_sys.h"
-#include "bta_sys_int.h"
+#include <hardware/bluetooth.h>
-#include "bta_av_api.h"
#include "a2d_api.h"
-#include "a2d_sbc.h"
#include "a2d_int.h"
-#include "bta_av_sbc.h"
+#include "a2d_sbc.h"
+#include "audio_a2dp_hw.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
#include "bta_av_ci.h"
-#include "l2c_api.h"
-
+#include "bta_av_sbc.h"
+#include "bta_sys.h"
+#include "bta_sys_int.h"
+#include "btif_av.h"
#include "btif_av_co.h"
#include "btif_media.h"
-
+#include "btif_sm.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "gki.h"
+#include "l2c_api.h"
#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
#include "osi/include/log.h"
#include "osi/include/thread.h"
#include "sbc_encoder.h"
#endif
-#include <hardware/bluetooth.h>
-#include "audio_a2dp_hw.h"
-#include "btif_av.h"
-#include "btif_sm.h"
-#include "btif_util.h"
#if (BTA_AV_SINK_INCLUDED == TRUE)
#include "oi_codec_sbc.h"
#include "oi_status.h"
#endif
-#include "stdio.h"
-#include <dlfcn.h>
#if (BTA_AV_SINK_INCLUDED == TRUE)
OI_CODEC_SBC_DECODER_CONTEXT context;
btif_media_aa_prep_2_send(0xFF);
/* send it */
- LOG_VERBOSE("btif_media_task_aa_handle_uipc_rx_rdy calls bta_av_ci_src_data_ready");
+ LOG_VERBOSE(LOG_TAG, "btif_media_task_aa_handle_uipc_rx_rdy calls bta_av_ci_src_data_ready");
bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
}
#endif
static void btif_media_thread_handle_cmd(fixed_queue_t *queue, UNUSED_ATTR void *context)
{
BT_HDR *p_msg = (BT_HDR *)fixed_queue_dequeue(queue);
- LOG_VERBOSE("btif_media_thread_handle_cmd : %d %s", p_msg->event,
+ LOG_VERBOSE(LOG_TAG, "btif_media_thread_handle_cmd : %d %s", p_msg->event,
dump_media_event(p_msg->event));
switch (p_msg->event)
APPL_TRACE_ERROR("ERROR in %s unknown event %d", __func__, p_msg->event);
}
GKI_freebuf(p_msg);
- LOG_VERBOSE("%s: %s DONE", __func__, dump_media_event(p_msg->event));
+ LOG_VERBOSE(LOG_TAG, "%s: %s DONE", __func__, dump_media_event(p_msg->event));
}
#if (BTA_AV_SINK_INCLUDED == TRUE)
btif_media_cb.decode_alarm = alarm_new();
if (!btif_media_cb.decode_alarm) {
- LOG_ERROR("%s unable to allocate decode alarm.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate decode alarm.", __func__);
return;
}
btif_media_cb.media_alarm = alarm_new();
if (!btif_media_cb.media_alarm) {
- LOG_ERROR("%s unable to allocate media alarm.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate media alarm.", __func__);
return;
}
}
btif_media_cb.media_feeding_state.pcm.counter -= result*pcm_bytes_per_frame;
- LOG_VERBOSE("WRITE %d FRAMES", result);
+ LOG_VERBOSE(LOG_TAG, "WRITE %d FRAMES", result);
}
break;
}
/* send it */
- LOG_VERBOSE("btif_media_send_aa_frame : send %d frames", nb_frame_2_send);
+ LOG_VERBOSE(LOG_TAG, "btif_media_send_aa_frame : send %d frames", nb_frame_2_send);
bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
}
*
*
***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_pan.h>
+
+#define LOG_TAG "bt_btif_pan"
+
#include <assert.h>
-#include <string.h>
-#include <signal.h>
#include <ctype.h>
-#include <sys/select.h>
-#include <sys/poll.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/if_ether.h>
+#include <linux/if_tun.h>
+#include <linux/sockios.h>
+#include <net/if.h>
#include <netdb.h>
+#include <netinet/in.h>
+#include <signal.h>
#include <stdio.h>
#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/select.h>
#include <sys/socket.h>
#include <sys/wait.h>
-#include <net/if.h>
-#include <linux/sockios.h>
-#include <sys/prctl.h>
-#include <linux/if_tun.h>
-#include <linux/if_ether.h>
+#include <unistd.h>
-#define LOG_TAG "bt_btif_pan"
-#include "btif_common.h"
-#include "btif_util.h"
-#include "btm_api.h"
-#include "btcore/include/bdaddr.h"
-#include "device/include/controller.h"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_pan.h>
#include "bta_api.h"
#include "bta_pan_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_pan_internal.h"
#include "btif_sock_thread.h"
#include "btif_sock_util.h"
-#include "btif_pan_internal.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "device/include/controller.h"
#include "gki.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#define FORWARD_IGNORE 1
#define FORWARD_SUCCESS 0
btpan_cb.flow = enable;
if (enable) {
btsock_thread_add_fd(pan_pth, btpan_cb.tap_fd, 0, SOCK_THREAD_FD_RD, 0);
- bta_dmexecutecallback(btu_exec_tap_fd_read, (void *)btpan_cb.tap_fd);
+ bta_dmexecutecallback(btu_exec_tap_fd_read, INT_TO_PTR(btpan_cb.tap_fd));
}
}
memcpy(packet, ð_hdr, sizeof(tETH_HDR));
if (len > TAP_MAX_PKT_WRITE_LEN)
{
- LOG_ERROR("btpan_tap_send eth packet size:%d is exceeded limit!", len);
+ LOG_ERROR(LOG_TAG, "btpan_tap_send eth packet size:%d is exceeded limit!", len);
return -1;
}
memcpy(packet + sizeof(tETH_HDR), buf, len);
bt_status_t status;
btpan_conn_t *conn = btpan_find_conn_handle(p_data->open.handle);
- LOG_VERBOSE("%s pan connection open status: %d", __func__, p_data->open.status);
+ LOG_VERBOSE(LOG_TAG, "%s pan connection open status: %d", __func__, p_data->open.status);
if (p_data->open.status == BTA_PAN_SUCCESS)
{
state = BTPAN_STATE_CONNECTED;
{
btpan_conn_t* conn = btpan_find_conn_handle(p_data->close.handle);
- LOG_INFO("%s: event = BTA_PAN_CLOSE_EVT handle %d", __FUNCTION__, p_data->close.handle);
+ LOG_INFO(LOG_TAG, "%s: event = BTA_PAN_CLOSE_EVT handle %d", __FUNCTION__, p_data->close.handle);
if (conn && conn->handle >= 0)
{
#define IS_EXCEPTION(e) ((e) & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL))
static void btu_exec_tap_fd_read(void *p_param) {
struct pollfd ufd;
- int fd = (int)p_param;
+ int fd = PTR_TO_INT(p_param);
if (fd == INVALID_FD || fd != btpan_cb.tap_fd)
return;
btpan_tap_close(fd);
btif_pan_close_all_conns();
} else if (flags & SOCK_THREAD_FD_RD)
- bta_dmexecutecallback(btu_exec_tap_fd_read, (void *)fd);
+ bta_dmexecutecallback(btu_exec_tap_fd_read, INT_TO_PTR(fd));
}
*
******************************************************************************/
+#define LOG_TAG "bt_btif_queue"
+
+#include "btif_profile_queue.h"
+
#include <assert.h>
#include <string.h>
-#include <hardware/bluetooth.h>
-#include <string.h>
-#define LOG_TAG "bt_btif_queue"
#include "btif_common.h"
-#include "btif_profile_queue.h"
#include "gki.h"
-#include "osi/include/list.h"
#include "osi/include/allocator.h"
+#include "osi/include/list.h"
#include "stack_manager.h"
/*******************************************************************************
for (const list_node_t *node = list_begin(connect_queue); node != list_end(connect_queue); node = list_next(node)) {
if (((connect_node_t *)list_node(node))->uuid == p_param->uuid) {
- LOG_INFO("%s dropping duplicate connect request for uuid: %04x", __func__, p_param->uuid);
+ LOG_INFO(LOG_TAG, "%s dropping duplicate connect request for uuid: %04x", __func__, p_param->uuid);
return;
}
}
return p_head->connect_cb(&p_head->bda, p_head->uuid);
}
-
/*******************************************************************************
**
** Function btif_queue_release
*
******************************************************************************/
-
/*****************************************************************************
*
* Filename: btif_rc.c
* Description: Bluetooth AVRC implementation
*
*****************************************************************************/
-#include <hardware/bluetooth.h>
+
+#define LOG_TAG "bt_btif_avrc"
+
#include <fcntl.h>
+#include <pthread.h>
#include <string.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_rc.h>
+
+#include "avrc_defs.h"
#include "bta_api.h"
#include "bta_av_api.h"
-#include "avrc_defs.h"
-#include "gki.h"
-
-#define LOG_TAG "bt_btif_avrc"
+#include "btif_av.h"
#include "btif_common.h"
#include "btif_util.h"
-#include "btif_av.h"
-#include "hardware/bt_rc.h"
+#include "gki.h"
#include "uinput.h"
/*****************************************************************************
rc_transaction_t transaction[MAX_TRANSACTIONS_PER_SESSION];
} rc_device_t;
-
rc_device_t device;
#define MAX_UINPUT_PATHS 3
extern BOOLEAN btif_hf_call_terminated_recently();
extern BOOLEAN check_cod(const bt_bdaddr_t *remote_bdaddr, uint32_t cod);
-
/*****************************************************************************
** Functions
******************************************************************************/
#endif
}
-
/***************************************************************************
* Function handle_rc_connect
*
}
-
/***************************************************************************
* Function handle_rc_metamsg_cmd
*
}
-
/*******************************************************************************
**
** Function btif_rc_upstreams_rsp_evt
return status;
}
-
/***************************************************************************
**
** Function register_volumechange
BTIF_TRACE_ERROR("%s failed to build command:%d",__FUNCTION__,BldResp);
}
-
/***************************************************************************
**
** Function handle_rc_metamsg_rsp
pmeta_msg->label);
}
-
/***************************************************************************
**
** Function cleanup
return result;
}
-
/*******************************************************************************
**
** Function release_transaction
*
***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_sdp.h>
+#define LOG_TAG "bt_btif_sdp"
+
#include <stdlib.h>
#include <string.h>
-#define LOG_TAG "BTIF_SDP"
-#include "btif_common.h"
-#include "btif_util.h"
-#include "btif_profile_queue.h"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+
#include "bta_api.h"
#include "bta_sdp_api.h"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
/*****************************************************************************
** Functions implemented in sdp_server.c
void copy_sdp_records(bluetooth_sdp_record* in_records,
bluetooth_sdp_record* out_records, int count);
-
/*****************************************************************************
** Static variables
******************************************************************************/
}
case BTA_SDP_CREATE_RECORD_USER_EVT:
{
- on_create_record_event((int)user_data);
+ on_create_record_event(PTR_TO_INT(user_data));
break;
}
case BTA_SDP_REMOVE_RECORD_USER_EVT:
{
- on_remove_record_event((int)user_data);
+ on_remove_record_event(PTR_TO_INT(user_data));
break;
}
default:
return BT_STATUS_SUCCESS;
}
-
static bt_status_t search(bt_bdaddr_t *bd_addr, const uint8_t *uuid)
{
- bdstr_t bdstr;
tSDP_UUID sdp_uuid;
sdp_uuid.len = 16;
memcpy(sdp_uuid.uu.uuid128, uuid, sizeof(sdp_uuid.uu.uuid128));
*
***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_sdp.h>
+#define LOG_TAG "bt_btif_sdp_server"
+
+#include <pthread.h>
#include <stdlib.h>
#include <string.h>
-#include <pthread.h>
-#define LOG_TAG "BTIF_SDP_SERVER"
-#include "allocator.h"
-#include "btif_common.h"
-#include "btif_util.h"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+
#include "bta_sdp_api.h"
#include "bta_sys.h"
-#include "utl.h"
+#include "btif_common.h"
#include "btif_sock_util.h"
+#include "btif_util.h"
+#include "osi/include/allocator.h"
+#include "utl.h"
static pthread_mutex_t sdp_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
* user2_ptr. */
static int alloc_sdp_slot(bluetooth_sdp_record* in_record) {
int i;
- char* tmp_ptr = NULL;
int record_size = get_sdp_records_size(in_record, 1);
bluetooth_sdp_record* record = osi_malloc(record_size);
BTIF_TRACE_DEBUG("%s() id=%d to handle=0x%08x", __FUNCTION__, id, handle);
}
-
bt_status_t create_sdp_record(bluetooth_sdp_record *record, int* record_handle) {
int handle;
if(handle < 0)
return BT_STATUS_FAIL;
- BTA_SdpCreateRecordByUser((void*) handle);
+ BTA_SdpCreateRecordByUser(INT_TO_PTR(handle));
*record_handle = handle;
/* Pass the actual record handle */
if(handle > 0) {
- BTA_SdpRemoveRecordByUser((void*) handle);
+ BTA_SdpRemoveRecordByUser(INT_TO_PTR(handle));
return BT_STATUS_SUCCESS;
}
BTIF_TRACE_DEBUG("Sdp Server %s - record already removed - or never created", __FUNCTION__);
return BT_STATUS_FAIL;
}
-
/******************************************************************************
* CALLBACK FUNCTIONS
* Called in BTA context to create/remove SDP records.
return sdp_handle;
}
-
/* Create a OPP Server SDP record based on information stored in a bluetooth_sdp_ops_record */
static int add_opps_sdp(const bluetooth_sdp_ops_record* rec)
{
}
return sdp_handle;
}
-
*
******************************************************************************/
-
/*****************************************************************************
*
* Filename: btif_sm.c
#define LOG_TAG "bt_btif"
-#include <hardware/bluetooth.h>
+#include "btif_sm.h"
-#include "osi/include/allocator.h"
#include "btif_common.h"
-#include "btif_sm.h"
#include "gki.h"
-
-/*****************************************************************************
-** Constants & Macros
-******************************************************************************/
-
+#include "osi/include/allocator.h"
/*****************************************************************************
** Local type definitions
} btif_sm_cb_t;
/*****************************************************************************
-** Static variables
-******************************************************************************/
-
-/*****************************************************************************
-** Static functions
-******************************************************************************/
-
-/*****************************************************************************
-** Externs
-******************************************************************************/
-
-/*****************************************************************************
** Functions
******************************************************************************/
#define LOG_TAG "bt_btif_sock"
#include <assert.h>
+
#include <hardware/bluetooth.h>
#include <hardware/bt_sock.h>
#include "bta_api.h"
#include "btif_common.h"
+#include "btif_sock_l2cap.h"
#include "btif_sock_rfc.h"
#include "btif_sock_sco.h"
-#include "btif_sock_thread.h"
-#include "btif_sock_l2cap.h"
#include "btif_sock_sdp.h"
+#include "btif_sock_thread.h"
#include "btif_util.h"
#include "osi/include/thread.h"
btsock_thread_init();
thread_handle = btsock_thread_create(btsock_signaled, NULL);
if (thread_handle == -1) {
- LOG_ERROR("%s unable to create btsock_thread.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create btsock_thread.", __func__);
goto error;
}
bt_status_t status = btsock_rfc_init(thread_handle);
if (status != BT_STATUS_SUCCESS) {
- LOG_ERROR("%s error initializing RFCOMM sockets: %d", __func__, status);
+ LOG_ERROR(LOG_TAG, "%s error initializing RFCOMM sockets: %d", __func__, status);
goto error;
}
status = btsock_l2cap_init(thread_handle);
if (status != BT_STATUS_SUCCESS) {
- LOG_ERROR("%s error initializing L2CAP sockets: %d", __func__, status);
+ LOG_ERROR(LOG_TAG, "%s error initializing L2CAP sockets: %d", __func__, status);
goto error;
}
thread = thread_new("btif_sock");
if (!thread) {
- LOG_ERROR("%s error creating new thread.", __func__);
+ LOG_ERROR(LOG_TAG, "%s error creating new thread.", __func__);
btsock_rfc_cleanup();
goto error;
}
status = btsock_sco_init(thread);
if (status != BT_STATUS_SUCCESS) {
- LOG_ERROR("%s error initializing SCO sockets: %d", __func__, status);
+ LOG_ERROR(LOG_TAG, "%s error initializing SCO sockets: %d", __func__, status);
btsock_rfc_cleanup();
goto error;
}
break;
default:
- LOG_ERROR("%s unknown/unsupported socket type: %d", __func__, type);
+ LOG_ERROR(LOG_TAG, "%s unknown/unsupported socket type: %d", __func__, type);
status = BT_STATUS_UNSUPPORTED;
break;
}
break;
default:
- LOG_ERROR("%s unknown/unsupported socket type: %d", __func__, type);
+ LOG_ERROR(LOG_TAG, "%s unknown/unsupported socket type: %d", __func__, type);
status = BT_STATUS_UNSUPPORTED;
break;
}
* limitations under the License.
*/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_sock.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#define LOG_TAG "bt_btif_sock"
+
+#include "btif_sock_l2cap.h"
+
#include <errno.h>
-#include <sys/ioctl.h>
#include <pthread.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <hardware/bt_sock.h>
-#define LOG_TAG "BTIF_SOCK"
#include "osi/include/allocator.h"
-#include "btif_common.h"
-#include "btif_util.h"
+#include "osi/include/log.h"
+#include "bt_target.h"
#include "bta_api.h"
-#include "btif_sock_thread.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "btif_common.h"
#include "btif_sock_sdp.h"
+#include "btif_sock_thread.h"
#include "btif_sock_util.h"
-#include "btif_sock_l2cap.h"
-#include "l2cdefs.h"
-
-#include "bt_target.h"
-#include "gki.h"
-#include "hcimsgs.h"
-#include "sdp_api.h"
-#include "btu.h"
+#include "btif_util.h"
#include "btm_api.h"
#include "btm_int.h"
-#include "bta_jv_api.h"
-#include "bta_jv_co.h"
-#include "port_api.h"
+#include "btu.h"
+#include "gki.h"
+#include "hcimsgs.h"
#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "port_api.h"
+#include "sdp_api.h"
-#include <cutils/log.h>
-#include <hardware/bluetooth.h>
#define asrt(s) if (!(s)) APPL_TRACE_ERROR("## %s assert %s failed at line:%d ##",__FUNCTION__, \
#s, __LINE__)
-static pthread_mutex_t slot_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
-
-
struct packet {
struct packet *next, *prev;
uint32_t len;
unsigned connected :1; //is connected?
unsigned outgoing_congest :1; //should we hold?
unsigned server_psm_sent :1; //The server shall only send PSM once.
-}l2cap_socket;
+} l2cap_socket;
static bt_status_t btSock_start_l2cap_server_l(l2cap_socket *sock);
struct packet *p = packet_alloc((const uint8_t*)data, len);
if (sock->bytes_buffered >= L2CAP_MAX_RX_BUFFER) {
- ALOGE("packet_put_tail_l: buffer overflow");
+ LOG_ERROR(LOG_TAG, "packet_put_tail_l: buffer overflow");
return FALSE;
}
if (!p) {
- ALOGE("packet_put_tail_l: unable to allocate packet...");
+ LOG_ERROR(LOG_TAG, "packet_put_tail_l: unable to allocate packet...");
return FALSE;
}
{
char ret;
-
pthread_mutex_lock(&state_lock);
ret = pth != -1;
pthread_mutex_unlock(&state_lock);
osi_free(sock);
}
-static void btsock_l2cap_free(l2cap_socket *sock)
-{
- pthread_mutex_lock(&state_lock);
- btsock_l2cap_free_l(sock);
- pthread_mutex_unlock(&state_lock);
-}
-
static l2cap_socket *btsock_l2cap_alloc_l(const char *name, const bt_bdaddr_t *addr,
char is_server, int flags)
{
return NULL;
}
-static l2cap_socket *btsock_l2cap_alloc(const char *name, const bt_bdaddr_t *addr,
- char is_server, int flags)
-{
- l2cap_socket *ret;
-
- pthread_mutex_lock(&state_lock);
- ret = btsock_l2cap_alloc_l(name, addr, is_server, flags);
- pthread_mutex_unlock(&state_lock);
-
- return ret;
-}
-
bt_status_t btsock_l2cap_init(int handle)
{
APPL_TRACE_DEBUG("btsock_l2cap_init...");
//if we do not set a callback, this socket will be dropped */
*(p_open->p_p_cback) = (void*)btsock_l2cap_cbk;
- *(p_open->p_user_data) = (void*)accept_rs->id;
+ *(p_open->p_user_data) = UINT_TO_PTR(accept_rs->id);
//start monitor the socket
btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_EXCEPTION, sock->id);
pthread_mutex_unlock(&state_lock);
}
-
-
static void on_l2cap_data_ind(tBTA_JV *evt, uint32_t id)
{
l2cap_socket *sock;
} else {
- tBTA_JV_DATA_IND *p_data_ind = &evt->data_ind;
UINT8 buffer[L2CAP_MAX_SDU_LENGTH];
UINT32 count;
static void btsock_l2cap_cbk(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
{
- int rc;
+ uint32_t sock_id = PTR_TO_UINT(user_data);
switch (event) {
case BTA_JV_L2CAP_START_EVT:
- on_srv_l2cap_listen_started(&p_data->l2c_start, (uint32_t)user_data);
+ on_srv_l2cap_listen_started(&p_data->l2c_start, sock_id);
break;
case BTA_JV_L2CAP_CL_INIT_EVT:
- on_cl_l2cap_init(&p_data->l2c_cl_init, (uint32_t)user_data);
+ on_cl_l2cap_init(&p_data->l2c_cl_init, sock_id);
break;
case BTA_JV_L2CAP_OPEN_EVT:
- on_l2cap_connect(p_data, (uint32_t)user_data);
- BTA_JvSetPmProfile(p_data->l2c_open.handle,BTA_JV_PM_ID_1,BTA_JV_CONN_OPEN);
+ on_l2cap_connect(p_data, sock_id);
+ BTA_JvSetPmProfile(p_data->l2c_open.handle, BTA_JV_PM_ID_1,BTA_JV_CONN_OPEN);
break;
case BTA_JV_L2CAP_CLOSE_EVT:
- APPL_TRACE_DEBUG("BTA_JV_L2CAP_CLOSE_EVT: user_data:%d", (uint32_t)user_data);
- on_l2cap_close(&p_data->l2c_close, (uint32_t)user_data);
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_CLOSE_EVT: id: %u", sock_id);
+ on_l2cap_close(&p_data->l2c_close, sock_id);
break;
case BTA_JV_L2CAP_DATA_IND_EVT:
- on_l2cap_data_ind(p_data, (uint32_t)user_data);
+ on_l2cap_data_ind(p_data, sock_id);
APPL_TRACE_DEBUG("BTA_JV_L2CAP_DATA_IND_EVT");
break;
break;
case BTA_JV_L2CAP_WRITE_EVT:
- APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_EVT id: %d", (int)user_data);
- on_l2cap_write_done((void*)p_data->l2c_write.req_id, (uint32_t)user_data);
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_EVT: id: %u", sock_id);
+ on_l2cap_write_done(UINT_TO_PTR(p_data->l2c_write.req_id), sock_id);
break;
case BTA_JV_L2CAP_WRITE_FIXED_EVT:
- APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_FIXED_EVT id: %d", (int)user_data);
- on_l2cap_write_fixed_done((void*)p_data->l2c_write_fixed.req_id, (uint32_t)user_data);
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_FIXED_EVT: id: %u", sock_id);
+ on_l2cap_write_fixed_done(UINT_TO_PTR(p_data->l2c_write_fixed.req_id), sock_id);
break;
case BTA_JV_L2CAP_CONG_EVT:
- on_l2cap_outgoing_congest(&p_data->l2c_cong, (uint32_t)user_data);
+ on_l2cap_outgoing_congest(&p_data->l2c_cong, sock_id);
break;
default:
- APPL_TRACE_ERROR("unhandled event %d, slot id:%d", event, (uint32_t)user_data);
+ APPL_TRACE_ERROR("unhandled event %d, slot id: %u", event, sock_id);
break;
}
}
if (sock->fixed_chan) {
if (BTA_JvL2capStartServerLE(sock->security, 0, NULL, sock->channel,
- L2CAP_DEFAULT_MTU, NULL, btsock_l2cap_cbk, (void*)sock->id)
+ L2CAP_DEFAULT_MTU, NULL, btsock_l2cap_cbk, UINT_TO_PTR(sock->id))
!= BTA_JV_SUCCESS)
stat = BT_STATUS_FAIL;
/* If we have a channel specified in the request, just start the server,
* else we request a PSM and start the server after we receive a PSM. */
if(sock->channel < 0) {
- if(BTA_JvGetChannelId(BTA_JV_CONN_TYPE_L2CAP, (void*)sock->id, 0)
+ if(BTA_JvGetChannelId(BTA_JV_CONN_TYPE_L2CAP, UINT_TO_PTR(sock->id), 0)
!= BTA_JV_SUCCESS)
stat = BT_STATUS_FAIL;
} else {
if (BTA_JvL2capStartServer(sock->security, 0, &obex_l2c_etm_opt,
- sock->channel, L2CAP_MAX_SDU_LENGTH, &cfg, btsock_l2cap_cbk, (void*)sock->id)
+ sock->channel, L2CAP_MAX_SDU_LENGTH, &cfg, btsock_l2cap_cbk, UINT_TO_PTR(sock->id))
!= BTA_JV_SUCCESS)
stat = BT_STATUS_FAIL;
}
if (fixed_chan) {
if (BTA_JvL2capConnectLE(sock->security, 0, NULL, channel,
L2CAP_DEFAULT_MTU, NULL, sock->addr.address, btsock_l2cap_cbk,
- (void*)sock->id) != BTA_JV_SUCCESS)
+ UINT_TO_PTR(sock->id)) != BTA_JV_SUCCESS)
stat = BT_STATUS_FAIL;
} else {
if (BTA_JvL2capConnect(sock->security, 0, &obex_l2c_etm_opt,
channel, L2CAP_MAX_SDU_LENGTH, &cfg, sock->addr.address,
- btsock_l2cap_cbk, (void*)sock->id) != BTA_JV_SUCCESS)
+ btsock_l2cap_cbk, UINT_TO_PTR(sock->id)) != BTA_JV_SUCCESS)
stat = BT_STATUS_FAIL;
}
}
* be wrong
* UPDATE: Since we are responsible for freeing the buffer in the
* write_complete_ind, it is OK to use malloc. */
-
int count = recv(fd, buffer, L2CAP_MAX_SDU_LENGTH,
MSG_NOSIGNAL | MSG_DONTWAIT);
APPL_TRACE_DEBUG("btsock_l2cap_signaled - %d bytes received from socket",
count);
+
+ // TODO(armansito): |buffer|, which is created above via
+ // malloc, is being cast below to UINT32 to be used as
+ // the |req_id| parameter of BTA_JvL2capWriteFixed and
+ // BTA_JvL2capWrite. The "id" then gets freed in an
+ // obscure callback elsewhere. We need to watch out for
+ // this type of unsafe practice, as this is error prone
+ // and difficult to follow.
if (sock->fixed_chan) {
if(BTA_JvL2capWriteFixed(sock->channel, (BD_ADDR*)&sock->addr,
- (UINT32)buffer, btsock_l2cap_cbk, buffer, count,
- (void *)user_id) != BTA_JV_SUCCESS) {
+ PTR_TO_UINT(buffer), btsock_l2cap_cbk, buffer, count,
+ UINT_TO_PTR(user_id)) != BTA_JV_SUCCESS) {
// On fail, free the buffer
on_l2cap_write_fixed_done(buffer, user_id);
}
} else {
- if(BTA_JvL2capWrite(sock->handle, (UINT32)buffer, buffer, count,
- (void *)user_id) != BTA_JV_SUCCESS) {
+ if(BTA_JvL2capWrite(sock->handle, PTR_TO_UINT(buffer), buffer, count,
+ UINT_TO_PTR(user_id)) != BTA_JV_SUCCESS) {
// On fail, free the buffer
on_l2cap_write_done(buffer, user_id);
}
pthread_mutex_unlock(&state_lock);
}
-
-
#include <assert.h>
#include <errno.h>
#include <features.h>
-#include <hardware/bluetooth.h>
-#include <hardware/bt_sock.h>
+#include <pthread.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
-#include <pthread.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
-#include "bta_api.h"
#include "bt_target.h"
+#include "bta_api.h"
#include "bta_jv_api.h"
#include "bta_jv_co.h"
#include "btif_common.h"
#include "btif_sock_sdp.h"
#include "btif_sock_thread.h"
#include "btif_sock_util.h"
-/* The JV interface can have only one user, hence we need to call a few
- * L2CAP functions from this file. */
-#include "btif_sock_l2cap.h"
-
-
#include "btif_util.h"
#include "btm_api.h"
#include "btm_int.h"
#include "hcimsgs.h"
#include "osi/include/compat.h"
#include "osi/include/list.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "port_api.h"
#include "sdp_api.h"
+/* The JV interface can have only one user, hence we need to call a few
+ * L2CAP functions from this file. */
+#include "btif_sock_l2cap.h"
+
#define MAX_RFC_CHANNEL 30 // Maximum number of RFCOMM channels (1-30 inclusive).
#define MAX_RFC_SESSION 7 // Maximum number of devices we can have an RFCOMM connection with.
if (rfc_slots[i].id == id)
return &rfc_slots[i];
- LOG_ERROR("%s unable to find RFCOMM slot id: %d", __func__, id);
+ LOG_ERROR(LOG_TAG, "%s unable to find RFCOMM slot id: %d", __func__, id);
return NULL;
}
rfc_slot_t *slot = find_free_slot();
if (!slot) {
- LOG_ERROR("%s unable to find free RFCOMM slot.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to find free RFCOMM slot.", __func__);
return NULL;
}
int fds[2] = { INVALID_FD, INVALID_FD };
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) == -1) {
- LOG_ERROR("%s error creating socketpair: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s error creating socketpair: %s", __func__, strerror(errno));
return NULL;
}
static rfc_slot_t *create_srv_accept_rfc_slot(rfc_slot_t *srv_rs, const bt_bdaddr_t *addr, int open_handle, int new_listen_handle) {
rfc_slot_t *accept_rs = alloc_rfc_slot(addr, srv_rs->service_name, srv_rs->service_uuid, srv_rs->scn, 0, false);
if (!accept_rs) {
- LOG_ERROR("%s unable to allocate RFCOMM slot.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
return NULL;
}
rfc_slot_t *slot = alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, true);
if (!slot) {
- LOG_ERROR("%s unable to allocate RFCOMM slot.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
goto out;
}
APPL_TRACE_DEBUG("BTA_JvGetChannelId: service_name: %s - channel: %d", service_name, channel);
- BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, (void*) slot->id, channel);
+ BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, UINT_TO_PTR(slot->id), channel);
*sock_fd = slot->app_fd; // Transfer ownership of fd to caller.
/*TODO:
* We are leaking one of the app_fd's - either the listen socket, or the connection socket.
rfc_slot_t *slot = alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, false);
if (!slot) {
- LOG_ERROR("%s unable to allocate RFCOMM slot.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
goto out;
}
if (is_uuid_empty(service_uuid)) {
tBTA_JV_STATUS ret = BTA_JvRfcommConnect(slot->security, slot->role, slot->scn, slot->addr.address, rfcomm_cback, (void *)(uintptr_t)slot->id);
if (ret != BTA_JV_SUCCESS) {
- LOG_ERROR("%s unable to initiate RFCOMM connection: %d", __func__, ret);
+ LOG_ERROR(LOG_TAG, "%s unable to initiate RFCOMM connection: %d", __func__, ret);
cleanup_rfc_slot(slot);
goto out;
}
if (!send_app_scn(slot)) {
- LOG_ERROR("%s unable to send channel number.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to send channel number.", __func__);
cleanup_rfc_slot(slot);
goto out;
}
if (send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1))
slot->f.connected = true;
else
- LOG_ERROR("%s unable to send connect completion signal to caller.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to send connect completion signal to caller.", __func__);
out:;
pthread_mutex_unlock(&slot_lock);
break;
default:
- LOG_ERROR("%s unhandled event %d, slot id: %zi", __func__, event, (uintptr_t)user_data);
+ LOG_ERROR(LOG_TAG, "%s unhandled event %d, slot id: %zi", __func__, event, (uintptr_t)user_data);
break;
}
return new_user_data;
}
static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data) {
- uint32_t id = (uintptr_t)user_data;
+ uint32_t id = PTR_TO_UINT(user_data);
switch(event) {
case BTA_JV_GET_SCN_EVT:
{
} else {
if(rs->is_service_uuid_valid == true) {
// We already have data for SDP record, create it (RFC-only profiles)
- BTA_JvCreateRecordByUser((void *)rs->id);
+ BTA_JvCreateRecordByUser(UINT_TO_PTR(rs->id));
} else {
APPL_TRACE_DEBUG("is_service_uuid_valid==false - don't set SDP-record, "
"just start the RFCOMM server", rs->id);
//now start the rfcomm server after sdp & channel # assigned
BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, MAX_RFC_SESSION,
- rfcomm_cback, (void*)rs->id);
+ rfcomm_cback, UINT_TO_PTR(rs->id));
}
}
} else if(rs) {
}
} else if (slot) {
// TODO(sharvil): this is really a logic error and we should probably assert.
- LOG_ERROR("%s SDP response returned but RFCOMM slot %d did not request SDP record.", __func__, id);
+ LOG_ERROR(LOG_TAG, "%s SDP response returned but RFCOMM slot %d did not request SDP record.", __func__, id);
}
} else if (slot) {
cleanup_rfc_slot(slot);
if (sent == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
return SENT_NONE;
- LOG_ERROR("%s error writing RFCOMM data back to app: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s error writing RFCOMM data back to app: %s", __func__, strerror(errno));
return SENT_FAILED;
}
pthread_mutex_unlock(&slot_lock);
BTA_JvRfcommWrite(slot->rfc_handle, slot->id);
} else {
- LOG_ERROR("%s socket signaled for read while disconnected, slot: %d, channel: %d", __func__, slot->id, slot->scn);
+ LOG_ERROR(LOG_TAG, "%s socket signaled for read while disconnected, slot: %d, channel: %d", __func__, slot->id, slot->scn);
need_close = true;
}
}
if (flags & SOCK_THREAD_FD_WR) {
// App is ready to receive more data, tell stack to enable data flow.
if (!slot->f.connected || !flush_incoming_que_on_wr_signal(slot)) {
- LOG_ERROR("%s socket signaled for write while disconnected (or write failure), slot: %d, channel: %d", __func__, slot->id, slot->scn);
+ LOG_ERROR(LOG_TAG, "%s socket signaled for write while disconnected (or write failure), slot: %d, channel: %d", __func__, slot->id, slot->scn);
need_close = true;
}
}
if (ioctl(slot->fd, FIONREAD, size) == 0) {
ret = true;
} else {
- LOG_ERROR("%s unable to determine bytes remaining to be read on fd %d: %s", __func__, slot->fd, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to determine bytes remaining to be read on fd %d: %s", __func__, slot->fd, strerror(errno));
cleanup_rfc_slot(slot);
}
if(received == size) {
ret = true;
} else {
- LOG_ERROR("%s error receiving RFCOMM data from app: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s error receiving RFCOMM data from app: %s", __func__, strerror(errno));
cleanup_rfc_slot(slot);
}
#include <assert.h>
#include <errno.h>
-#include <hardware/bluetooth.h>
-#include <hardware/bt_sock.h>
+#include <pthread.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
#include "btif_common.h"
#include "osi/include/allocator.h"
#include "osi/include/list.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/socket.h"
#include "osi/include/thread.h"
sco_socket_t *sco_socket = NULL;
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pair) == -1) {
- LOG_ERROR("%s unable to allocate socket pair: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to allocate socket pair: %s", __func__, strerror(errno));
goto error;
}
sco_socket = sco_socket_new();
if (!sco_socket) {
- LOG_ERROR("%s unable to allocate new SCO socket.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate new SCO socket.", __func__);
goto error;
}
tBTM_STATUS status = BTM_CreateSco((uint8_t *)bd_addr, !is_listening, sco_parameters.packet_types, &sco_socket->sco_handle, connect_completed_cb, disconnect_completed_cb);
if (status != BTM_CMD_STARTED) {
- LOG_ERROR("%s unable to create SCO socket: %d", __func__, status);
+ LOG_ERROR(LOG_TAG, "%s unable to create SCO socket: %d", __func__, status);
goto error;
}
socket_t *socket = socket_new_from_fd(pair[1]);
if (!socket) {
- LOG_ERROR("%s unable to allocate socket from file descriptor %d.", __func__, pair[1]);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate socket from file descriptor %d.", __func__, pair[1]);
goto error;
}
int client_fd = INVALID_FD;
if (!sco_socket) {
- LOG_ERROR("%s unable to find sco_socket for handle: %hu", __func__, conn_data->sco_inx);
+ LOG_ERROR(LOG_TAG, "%s unable to find sco_socket for handle: %hu", __func__, conn_data->sco_inx);
goto error;
}
if (sco_socket != listen_sco_socket) {
- LOG_ERROR("%s received connection request on non-listening socket handle: %hu", __func__, conn_data->sco_inx);
+ LOG_ERROR(LOG_TAG, "%s received connection request on non-listening socket handle: %hu", __func__, conn_data->sco_inx);
goto error;
}
sco_socket_t *new_sco_socket = sco_socket_establish_locked(true, NULL, &client_fd);
if (!new_sco_socket) {
- LOG_ERROR("%s unable to allocate new sco_socket.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate new sco_socket.", __func__);
goto error;
}
connect_signal.status = 0;
if (socket_write_and_transfer_fd(sco_socket->socket, &connect_signal, sizeof(connect_signal), client_fd) != sizeof(connect_signal)) {
- LOG_ERROR("%s unable to send new file descriptor to listening socket.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to send new file descriptor to listening socket.", __func__);
goto error;
}
sco_socket_t *sco_socket = sco_socket_find_locked(sco_handle);
if (!sco_socket) {
- LOG_ERROR("%s SCO socket not found on connect for handle: %hu", __func__, sco_handle);
+ LOG_ERROR(LOG_TAG, "%s SCO socket not found on connect for handle: %hu", __func__, sco_handle);
goto out;
}
sco_socket_t *sco_socket = sco_socket_find_locked(sco_handle);
if (!sco_socket) {
- LOG_ERROR("%s SCO socket not found on disconnect for handle: %hu", __func__, sco_handle);
+ LOG_ERROR(LOG_TAG, "%s SCO socket not found on disconnect for handle: %hu", __func__, sco_handle);
goto out;
}
#define LOG_TAG "bt_btif_sock_sdp"
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#include "btif_sock_sdp.h"
+
#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_sock.h>
+#include "../bta/pb/bta_pbs_int.h"
+#include "../include/bta_op_api.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
#include "btif_common.h"
-#include "btif_util.h"
#include "btif_sock_util.h"
-#include "bta_api.h"
-#include "bt_target.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
#include "gki.h"
#include "hcimsgs.h"
#include "sdp_api.h"
-#include "btu.h"
-#include "btm_api.h"
-#include "btm_int.h"
-#include "btif_sock_sdp.h"
#include "utl.h"
-#include "../bta/pb/bta_pbs_int.h"
-#include "../include/bta_op_api.h"
-#include "bta_jv_api.h"
// This module provides an abstraction on top of the lower-level SDP database
// code for registration and discovery of various bluetooth sockets.
| BTA_OP_ANY_MASK)
#endif
-
-
#define RESERVED_SCN_PBS 19
#define RESERVED_SCN_OPS 12
1, &type, &type_len, &type_buf_ptr))
goto error;
-
APPL_TRACE_DEBUG("add_sdp_by_uuid: service registered successfully, "
"service_name: %s, handle: 0x%08x", name, handle);
return handle;
*
***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_sock.h>
+#define LOG_TAG "bt_btif_sock"
-//bta_jv_co_rfc_data
-#include <stdio.h>
-#include <stdlib.h>
+#include "btif_sock_thread.h"
+
+#include <alloca.h>
+#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <features.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
+#include <sys/poll.h>
+#include <sys/select.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <sys/un.h>
#include <time.h>
-#include <fcntl.h>
#include <unistd.h>
-#include <signal.h>
-#include <pthread.h>
-#include <ctype.h>
-
-#include <sys/select.h>
-#include <sys/poll.h>
-#include <cutils/sockets.h>
-#include <alloca.h>
-
-#define LOG_TAG "bt_btif_sock"
-#include "btif_common.h"
-#include "btif_util.h"
-
#include "bta_api.h"
+#include "btif_common.h"
#include "btif_sock.h"
-#include "btif_sock_thread.h"
#include "btif_sock_util.h"
+#include "btif_util.h"
+#include "osi/include/socket_utils/sockets.h"
#define asrt(s) if(!(s)) APPL_TRACE_ERROR("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
#define print_events(events) do { \
} thread_slot_t;
static thread_slot_t ts[MAX_THREAD];
-
-
static void *sock_poll_thread(void *arg);
static inline void close_cmd_fd(int h);
if(s < 0)
return -1;
APPL_TRACE_DEBUG("covert name to android abstract name:%s", name);
- if(socket_local_server_bind(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT) >= 0)
+ if(osi_socket_local_server_bind(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT) >= 0)
{
if(listen(s, 5) == 0)
{
if(s < 0)
return -1;
set_socket_blocking(s, TRUE);
- if(socket_local_client_connect(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) >= 0)
+ if(osi_socket_local_client_connect(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) >= 0)
{
APPL_TRACE_DEBUG("connected to local socket:%s, fd:%d", name, s);
return s;
*
******************************************************************************/
+#define LOG_TAG "bt_btif_sock"
-/************************************************************************************
- *
- * Filename: btif_hf.c
- *
- * Description: Handsfree Profile Bluetooth Interface
- *
- *
- ***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_sock.h>
+#include "btif_sock_util.h"
+
+#include <arpa/inet.h>
#include <errno.h>
-#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
+#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <sys/un.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <errno.h>
#include <unistd.h>
-#include <sys/ioctl.h>
-
-#include <cutils/sockets.h>
-#include <netinet/tcp.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
-#define LOG_TAG "bt_btif_sock"
-#include "btif_common.h"
-#include "btif_util.h"
-
+#include "bt_target.h"
#include "bta_api.h"
-#include "btif_sock_thread.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "btif_common.h"
#include "btif_sock_sdp.h"
-
-#include "bt_target.h"
-#include "gki.h"
-#include "hcimsgs.h"
-#include "sdp_api.h"
-#include "btu.h"
+#include "btif_sock_thread.h"
+#include "btif_util.h"
#include "btm_api.h"
#include "btm_int.h"
-#include "bta_jv_api.h"
-#include "bta_jv_co.h"
-#include "port_api.h"
+#include "btu.h"
+#include "gki.h"
+#include "hcimsgs.h"
#include "osi/include/log.h"
+#include "port_api.h"
+#include "sdp_api.h"
#define asrt(s) if(!(s)) BTIF_TRACE_ERROR("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
-
int sock_send_all(int sock_fd, const uint8_t* buf, int len)
{
int s = len;
return ret_len;
}
-
-#define PRINT(s) __android_log_write(ANDROID_LOG_DEBUG, NULL, s)
static const char* hex_table = "0123456789abcdef";
static inline void byte2hex(const char* data, char** str)
{
char *line;
int i, j, addr;
const int width = 16;
- LOG_DEBUG("%s, size:%d, dump started {", title, size);
+ LOG_DEBUG(LOG_TAG, "%s, size:%d, dump started {", title, size);
if(size <= 0)
return;
//write offset
*line++ = ' ';
}
*line = 0;
- PRINT(line_buff);
+ LOG_DEBUG(LOG_TAG, "%s", line_buff);
for(i = 0; i < size / width; i++)
{
//wirte the end of line
*line = 0;
//output the line
- PRINT(line_buff);
+ LOG_DEBUG(LOG_TAG, "%s", line_buff);
}
//last line of left over if any
int leftover = size % width;
//write the end of line
*line = 0;
//output the line
- PRINT(line_buff);
+ LOG_DEBUG(LOG_TAG, "%s", line_buff);
}
- LOG_DEBUG("%s, size:%d, dump ended }", title, size);
+ LOG_DEBUG(LOG_TAG, "%s, size:%d, dump ended }", title, size);
}
*
*
*/
+
+#define LOG_TAG "bt_btif_storage"
+
+#include "btif_storage.h"
+
+#include <alloca.h>
#include <assert.h>
+#include <ctype.h>
#include <stdlib.h>
-#include <time.h>
#include <string.h>
-#include <ctype.h>
-#include <alloca.h>
-
-
-#include <hardware/bluetooth.h>
-#include "btif_config.h"
-#define LOG_TAG "bt_btif_storage"
+#include <time.h>
+#include "bta_hh_api.h"
+#include "btcore/include/bdaddr.h"
#include "btif_api.h"
-#include "btif_storage.h"
+#include "btif_config.h"
+#include "btif_hh.h"
#include "btif_util.h"
-#include "btcore/include/bdaddr.h"
+#include "gki.h"
#include "osi/include/allocator.h"
#include "osi/include/compat.h"
#include "osi/include/config.h"
-#include "gki.h"
-#include "osi/include/osi.h"
-#include "bta_hh_api.h"
-#include "btif_hh.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
/************************************************************************************
** 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"
#define BTIF_STORAGE_KEY_ADAPTER_SCANMODE "ScanMode"
#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"
#define BTIF_AUTO_PAIR_CONF_VALUE_SEPARATOR ","
-
/* This is a local property to add a device found */
#define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF
STORAGE_HID_DESC_LEN_SIZE+ 1 +\
STORAGE_HID_DESC_MAX_SIZE+ 1 )
-
/* currently remote services is the potentially largest entry */
#define BTIF_STORAGE_MAX_LINE_SZ BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX
-
/* check against unv max entry size at compile time */
#if (BTIF_STORAGE_ENTRY_MAX_SIZE > UNV_MAXLINE_LENGTH)
#error "btif storage entry size exceeds unv max line size"
#endif
-
#define BTIF_STORAGE_HL_APP "hl_app"
#define BTIF_STORAGE_HL_APP_CB "hl_app_cb"
#define BTIF_STORAGE_HL_APP_DATA "hl_app_data_"
uint32_t i;
tBTA_SERVICE_MASK service_mask = btif_get_enabled_services_mask();
- LOG_INFO("%s service_mask:0x%x", __FUNCTION__, service_mask);
+ LOG_INFO(LOG_TAG, "%s service_mask:0x%x", __FUNCTION__, service_mask);
for (i=0; i < BTA_MAX_SERVICE_ID; i++)
{
/* This should eventually become a function when more services are enabled */
{
int device_type;
int addr_type;
- UINT32 i;
bt_bdaddr_t bd_addr;
BD_ADDR bta_bd_addr;
bool device_added = false;
return bt_status;
}
-
/*******************************************************************************
**
** Function btif_storage_load_autopair_device_list
config_t *config = config_new(BTIF_AUTO_PAIR_CONF_FILE);
if (!config) {
- LOG_ERROR("%s failed to open auto pair blacklist conf file '%s'.", __func__, BTIF_AUTO_PAIR_CONF_FILE);
+ LOG_ERROR(LOG_TAG, "%s failed to open auto pair blacklist conf file '%s'.", __func__, BTIF_AUTO_PAIR_CONF_FILE);
return BT_STATUS_FAIL;
}
*
***********************************************************************************/
-#include <hardware/bluetooth.h>
-#include <hardware/bt_hf.h>
-#include <hardware/bt_av.h>
+#define LOG_TAG "bt_btif_util"
+
+#include "btif_util.h"
+
+#include <ctype.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
+#include <hardware/bt_av.h>
-#define LOG_TAG "bt_btif_util"
-#include "btif_common.h"
-#include "bta_api.h"
-#include "gki.h"
-#include "btu.h"
-#include "bte.h"
-#include "btif_dm.h"
-#include "btif_util.h"
+#include "avrc_defs.h"
#include "bta_ag_api.h"
+#include "bta_api.h"
#include "bta_av_api.h"
-#include "bta_hh_api.h"
#include "bta_hf_client_api.h"
-#include "avrc_defs.h"
+#include "bta_hh_api.h"
+#include "bte.h"
+#include "btif_common.h"
+#include "btif_dm.h"
+#include "btu.h"
+#include "gki.h"
/************************************************************************************
** Constants & Macros
return (x);
}
-
const char* dump_dm_search_event(UINT16 event)
{
switch(event)
}
}
-
const char* dump_property_type(bt_property_type_t type)
{
switch(type)
}
}
-
const char* dump_hf_conn_state(UINT16 event)
{
switch(event)
}
}
-
const char* dump_hf_audio_state(UINT16 event)
{
switch(event)
#define LOG_TAG "bt_stack_manager"
+#include "stack_manager.h"
+
#include <hardware/bluetooth.h>
+#include "btcore/include/module.h"
+#include "btcore/include/osi_module.h"
#include "btif_api.h"
#include "btif_common.h"
#include "device/include/controller.h"
-#include "btcore/include/module.h"
-#include "btcore/include/osi_module.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/semaphore.h"
-#include "stack_manager.h"
#include "osi/include/thread.h"
// Temp includes
static void ensure_stack_is_initialized(void) {
if (!stack_is_initialized) {
- LOG_WARN("%s found the stack was uninitialized. Initializing now.", __func__);
+ LOG_WARN(LOG_TAG, "%s found the stack was uninitialized. Initializing now.", __func__);
// No semaphore needed since we are calling it directly
event_init_stack(NULL);
}
// Synchronous function to start up the stack
static void event_start_up_stack(UNUSED_ATTR void *context) {
if (stack_is_running) {
- LOG_DEBUG("%s stack already brought up.", __func__);
+ LOG_DEBUG(LOG_TAG, "%s stack already brought up.", __func__);
return;
}
ensure_stack_is_initialized();
- LOG_DEBUG("%s is bringing up the stack.", __func__);
+ LOG_DEBUG(LOG_TAG, "%s is bringing up the stack.", __func__);
hack_future = future_new();
// Include this for now to put btif config into a shutdown-able state
}
stack_is_running = true;
- LOG_DEBUG("%s finished", __func__);
+ LOG_DEBUG(LOG_TAG, "%s finished", __func__);
btif_thread_post(event_signal_stack_up, NULL);
}
// Synchronous function to shut down the stack
static void event_shut_down_stack(UNUSED_ATTR void *context) {
if (!stack_is_running) {
- LOG_DEBUG("%s stack is already brought down.", __func__);
+ LOG_DEBUG(LOG_TAG, "%s stack is already brought down.", __func__);
return;
}
- LOG_DEBUG("%s is bringing down the stack.", __func__);
+ LOG_DEBUG(LOG_TAG, "%s is bringing down the stack.", __func__);
hack_future = future_new();
stack_is_running = false;
future_await(hack_future);
module_shut_down(get_module(CONTROLLER_MODULE)); // Doesn't do any work, just puts it in a restartable state
- LOG_DEBUG("%s finished.", __func__);
+ LOG_DEBUG(LOG_TAG, "%s finished.", __func__);
btif_thread_post(event_signal_stack_down, NULL);
}
static void ensure_stack_is_not_running(void) {
if (stack_is_running) {
- LOG_WARN("%s found the stack was still running. Bringing it down now.", __func__);
+ LOG_WARN(LOG_TAG, "%s found the stack was still running. Bringing it down now.", __func__);
event_shut_down_stack(NULL);
}
}
// Synchronous function to clean up the stack
static void event_clean_up_stack(UNUSED_ATTR void *context) {
if (!stack_is_initialized) {
- LOG_DEBUG("%s found the stack already in a clean state.", __func__);
+ LOG_DEBUG(LOG_TAG, "%s found the stack already in a clean state.", __func__);
return;
}
ensure_stack_is_not_running();
- LOG_DEBUG("%s is cleaning up the stack.", __func__);
+ LOG_DEBUG(LOG_TAG, "%s is cleaning up the stack.", __func__);
hack_future = future_new();
stack_is_initialized = false;
future_await(hack_future);
module_clean_up(get_module(OSI_MODULE));
module_management_stop();
- LOG_DEBUG("%s finished.", __func__);
+ LOG_DEBUG(LOG_TAG, "%s finished.", __func__);
}
static void event_signal_stack_up(UNUSED_ATTR void *context) {
management_thread = thread_new("stack_manager");
if (!management_thread) {
- LOG_ERROR("%s unable to create stack management thread.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create stack management thread.", __func__);
return;
}
}
--- /dev/null
+#
+# 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.
+#
+
+declare_args() {
+ # Include path for hardware/bluetooth.h
+ libhw_include_path = ""
+ core_include_path = ""
+}
+
+config("default_include_dirs") {
+ # TODO(armansito): Remove "core_include_path" once the cutils includes have
+ # been removed.
+ assert(libhw_include_path != "", "libhardware_include_path build argument wasn't provided.")
+ assert(core_include_path != "", "core_include_path build argument wasn't provided.")
+ include_dirs = [
+ libhw_include_path,
+ core_include_path,
+ ]
+}
+
+config("linux") {
+ # TODO(keybuk): AndroidConfig.h or equivalent
+
+ cflags = [
+ "-Wall",
+ "-Werror",
+ "-g",
+ "-O0",
+ "-fpic",
+ "-fdata-sections",
+ "-ffunction-sections",
+ "-fvisibility=hidden",
+ ]
+
+ cflags_c = [
+ "-std=c99"
+ ]
+
+ cflags_cc = [
+ "-std=c++11",
+ "-fno-exceptions",
+ ]
+
+ defines = [
+ "_FORTIFY_SOURCE=2",
+ "_GNU_SOURCE",
+ "HAS_NO_BDROID_BUILDCFG",
+ "LOG_NDEBUG=1",
+ "EXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
+
+ # This is a macro to that can be used by source code to detect if the
+ # current build is done by GN or via Android.mk. This is a temporary
+ # workaround until we can remove all Android-specific dependencies.
+ "OS_GENERIC",
+ ]
+}
+
+config("pic") {
+ cflags = [ "-fPIC" ]
+}
+
+config("gc") {
+ ldflags = [ "-Wl,--gc-sections" ]
+}
--- /dev/null
+#
+# 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.
+#
+
+set_default_toolchain("//build/toolchain/gcc")
+
+set_defaults("executable") {
+ configs = [
+ "//build:linux",
+ "//build:gc",
+ "//build:default_include_dirs",
+ ]
+}
+
+set_defaults("shared_library") {
+ configs = [
+ "//build:linux",
+ "//build:gc",
+ "//build:default_include_dirs",
+ ]
+}
+
+set_defaults("source_set") {
+ configs = [
+ "//build:linux",
+ "//build:gc",
+ "//build:default_include_dirs",
+ ]
+}
+
+set_defaults("static_library") {
+ configs = [
+ "//build:linux",
+ "//build:gc",
+ "//build:default_include_dirs",
+ ]
+}
--- /dev/null
+#
+# 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.
+#
+
+config("gtest_config") {
+ # Gtest headers need to be able to find themselves.
+ include_dirs = [ "include" ]
+
+ defines = [ "GTEST_HAS_RTTI=0" ]
+}
+
+config("gtest_direct_config") {
+ visibility = [ ":*" ]
+ defines = [ "UNIT_TEST" ]
+}
+
+static_library("gtest") {
+ testonly = true
+ sources = [
+ "include/gtest/gtest-death-test.h",
+ "include/gtest/gtest-message.h",
+ "include/gtest/gtest-param-test.h",
+ "include/gtest/gtest-printers.h",
+ "include/gtest/gtest-spi.h",
+ "include/gtest/gtest-test-part.h",
+ "include/gtest/gtest-typed-test.h",
+ "include/gtest/gtest.h",
+ "include/gtest/gtest_pred_impl.h",
+ "include/gtest/internal/gtest-death-test-internal.h",
+ "include/gtest/internal/gtest-filepath.h",
+ "include/gtest/internal/gtest-internal.h",
+ "include/gtest/internal/gtest-linked_ptr.h",
+ "include/gtest/internal/gtest-param-util-generated.h",
+ "include/gtest/internal/gtest-param-util.h",
+ "include/gtest/internal/gtest-port.h",
+ "include/gtest/internal/gtest-string.h",
+ "include/gtest/internal/gtest-tuple.h",
+ "include/gtest/internal/gtest-type-util.h",
+
+ "src/gtest-all.cc",
+ "src/gtest-death-test.cc",
+ "src/gtest-filepath.cc",
+ "src/gtest-internal-inl.h",
+ "src/gtest-port.cc",
+ "src/gtest-printers.cc",
+ "src/gtest-test-part.cc",
+ "src/gtest-typed-test.cc",
+ "src/gtest.cc",
+ ]
+
+ include_dirs = [ "." ]
+
+ all_dependent_configs = [ ":gtest_config" ]
+ public_configs = [ ":gtest_direct_config" ]
+}
+
+source_set("gtest_main") {
+ testonly = true
+ sources = [
+ "src/gtest_main.cc",
+ ]
+ deps = [
+ ":gtest",
+ ]
+}
--- /dev/null
+#
+# 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.
+#
+
+source_set("base_sources") {
+ sources = [
+ "base/allocator/type_profiler_control.cc",
+ "base/at_exit.cc",
+ "base/atomic_ref_count.h",
+ "base/atomic_sequence_num.h",
+ "base/atomicops.h",
+ "base/atomicops_internals_x86_gcc.cc",
+ "base/base64.cc",
+ "base/base64.h",
+ "base/base_export.h",
+ "base/base_switches.cc",
+ "base/bind_helpers.cc",
+ "base/build_time.cc",
+ "base/callback_helpers.cc",
+ "base/callback_internal.cc",
+ "base/command_line.cc",
+ "base/cpu.cc",
+ "base/debug/alias.cc",
+ "base/debug/debugger.cc",
+ "base/debug/debugger_posix.cc",
+ "base/debug/stack_trace.cc",
+ "base/debug/stack_trace_posix.cc",
+ "base/debug/task_annotator.cc",
+ "base/environment.cc",
+ "base/files/file.cc",
+ "base/files/file_enumerator.cc",
+ "base/files/file_enumerator_posix.cc",
+ "base/files/file_path.cc",
+ "base/files/file_path_constants.cc",
+ "base/files/file_path_watcher.cc",
+ "base/files/file_path_watcher_linux.cc",
+ "base/files/file_posix.cc",
+ "base/files/file_tracing.cc",
+ "base/files/file_util.cc",
+ "base/files/file_util_linux.cc",
+ "base/files/file_util_posix.cc",
+ "base/files/important_file_writer.cc",
+ "base/files/scoped_file.cc",
+ "base/files/scoped_temp_dir.cc",
+ "base/guid.cc",
+ "base/guid_posix.cc",
+ "base/hash.cc",
+ "base/json/json_parser.cc",
+ "base/json/json_reader.cc",
+ "base/json/json_string_value_serializer.cc",
+ "base/json/json_writer.cc",
+ "base/json/string_escape.cc",
+ "base/lazy_instance.cc",
+ "base/location.cc",
+ "base/logging.cc",
+ "base/md5.cc",
+ "base/memory/ref_counted.cc",
+ "base/memory/ref_counted_memory.cc",
+ "base/memory/singleton.cc",
+ "base/memory/weak_ptr.cc",
+ "base/message_loop/incoming_task_queue.cc",
+ "base/message_loop/message_loop.cc",
+ "base/message_loop/message_loop_proxy.cc",
+ "base/message_loop/message_loop_proxy_impl.cc",
+ "base/message_loop/message_pump.cc",
+ "base/message_loop/message_pump_default.cc",
+ "base/message_loop/message_pump_libevent.cc",
+ "base/metrics/bucket_ranges.cc",
+ "base/metrics/field_trial.cc",
+ "base/metrics/histogram_base.cc",
+ "base/metrics/histogram.cc",
+ "base/metrics/histogram_samples.cc",
+ "base/metrics/histogram_snapshot_manager.cc",
+ "base/metrics/sample_map.cc",
+ "base/metrics/sample_vector.cc",
+ "base/metrics/sparse_histogram.cc",
+ "base/metrics/statistics_recorder.cc",
+ "base/pending_task.cc",
+ "base/pickle.cc",
+ "base/posix/file_descriptor_shuffle.cc",
+ "base/posix/safe_strerror.cc",
+ "base/posix/unix_domain_socket_linux.cc",
+ "base/process/internal_linux.cc",
+ "base/process/kill.cc",
+ "base/process/kill_posix.cc",
+ "base/process/launch.cc",
+ "base/process/launch_posix.cc",
+ "base/process/process_handle_linux.cc",
+ "base/process/process_handle_posix.cc",
+ "base/process/process_iterator.cc",
+ "base/process/process_iterator_linux.cc",
+ "base/process/process_metrics.cc",
+ "base/process/process_metrics_linux.cc",
+ "base/process/process_metrics_posix.cc",
+ "base/process/process_posix.cc",
+ "base/profiler/alternate_timer.cc",
+ "base/profiler/scoped_profile.cc",
+ "base/profiler/scoped_tracker.cc",
+ "base/profiler/tracked_time.cc",
+ "base/rand_util.cc",
+ "base/rand_util_posix.cc",
+ "base/run_loop.cc",
+ "base/sequence_checker_impl.cc",
+ "base/sequenced_task_runner.cc",
+ "base/sha1_portable.cc",
+ "base/strings/safe_sprintf.cc",
+ "base/strings/string16.cc",
+ "base/strings/string_number_conversions.cc",
+ "base/strings/string_piece.cc",
+ "base/strings/stringprintf.cc",
+ "base/strings/string_split.cc",
+ "base/strings/string_util.cc",
+ "base/strings/string_util_constants.cc",
+ "base/strings/sys_string_conversions_posix.cc",
+ "base/strings/utf_string_conversions.cc",
+ "base/strings/utf_string_conversion_utils.cc",
+ "base/synchronization/cancellation_flag.cc",
+ "base/synchronization/condition_variable_posix.cc",
+ "base/synchronization/lock.cc",
+ "base/synchronization/lock_impl_posix.cc",
+ "base/synchronization/waitable_event_posix.cc",
+ "base/sync_socket_posix.cc",
+ "base/sys_info.cc",
+ # TODO(armansito): For our GN builds these platform-specific implementations
+ # don't really make that much sense but instead of removing the line I'm
+ # commenting it out in case we want to re-add it later (it's included in the
+ # libchrome Android.mk).
+ #"sys_info_chromeos.cc",
+ "base/sys_info_linux.cc",
+ "base/sys_info_posix.cc",
+ "base/task/cancelable_task_tracker.cc",
+ "base/task_runner.cc",
+ "base/third_party/dmg_fp/dtoa.cc",
+ "base/third_party/dmg_fp/g_fmt.cc",
+ "base/third_party/dynamic_annotations/dynamic_annotations.c",
+ "base/third_party/icu/icu_utf.cc",
+ "base/third_party/nspr/prtime.cc",
+ "base/third_party/superfasthash/superfasthash.c",
+ "base/threading/non_thread_safe_impl.cc",
+ "base/threading/platform_thread_internal_posix.cc",
+ "base/threading/platform_thread_linux.cc",
+ "base/threading/platform_thread_posix.cc",
+ "base/threading/post_task_and_reply_impl.cc",
+ "base/threading/sequenced_worker_pool.cc",
+ "base/threading/simple_thread.cc",
+ "base/threading/thread.cc",
+ "base/threading/thread_checker_impl.cc",
+ "base/threading/thread_collision_warner.cc",
+ "base/threading/thread_id_name_manager.cc",
+ "base/threading/thread_local_posix.cc",
+ "base/threading/thread_local_storage.cc",
+ "base/threading/thread_local_storage_posix.cc",
+ "base/threading/thread_restrictions.cc",
+ "base/threading/worker_pool.cc",
+ "base/threading/worker_pool_posix.cc",
+ "base/thread_task_runner_handle.cc",
+ "base/time/clock.cc",
+ "base/time/default_clock.cc",
+ "base/time/default_tick_clock.cc",
+ "base/timer/elapsed_timer.cc",
+ "base/timer/timer.cc",
+ "base/time/tick_clock.cc",
+ "base/time/time.cc",
+ "base/time/time_posix.cc",
+ "base/trace_event/malloc_dump_provider.cc",
+ "base/trace_event/memory_allocator_dump.cc",
+ "base/trace_event/memory_allocator_dump_guid.cc",
+ "base/trace_event/memory_dump_manager.cc",
+ "base/trace_event/memory_dump_session_state.cc",
+ "base/trace_event/process_memory_dump.cc",
+ "base/trace_event/process_memory_maps.cc",
+ "base/trace_event/process_memory_maps_dump_provider.cc",
+ "base/trace_event/process_memory_totals.cc",
+ "base/trace_event/process_memory_totals_dump_provider.cc",
+ "base/trace_event/trace_config.cc",
+ "base/trace_event/trace_event_argument.cc",
+ "base/trace_event/trace_event_impl.cc",
+ "base/trace_event/trace_event_impl_constants.cc",
+ "base/trace_event/trace_event_memory.cc",
+ "base/trace_event/trace_event_memory_overhead.cc",
+ "base/trace_event/trace_event_synthetic_delay.cc",
+ "base/tracked_objects.cc",
+ "base/tracking_info.cc",
+ "base/values.cc",
+ "base/vlog.cc",
+ ]
+
+ defines = [ "BASE_IMPLEMENTATION" ]
+
+ include_dirs = [
+ "//",
+ "//third_party/libchrome",
+ "//third_party/libchrome/base",
+ "//third_party/modp_b64",
+ ]
+}
+
+static_library("base") {
+ deps = [
+ ":base_sources",
+ ]
+
+ cflags = [
+ "-Wno-char-subscripts",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-function",
+ "-Wno-unused_parameter",
+ ]
+ cflags_cc = [
+ "-Wno-deprecated-register",
+ "-Wno-non-virtual-dtor",
+ "-Wno-sign-promo",
+ ]
+
+ libs = [ "-levent", "-levent_core", "-lpthread" ]
+}
--- /dev/null
+#
+# 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.
+#
+
+static_library("tinyxml2") {
+ sources = [
+ "tinyxml2.cpp"
+ ]
+
+ include_dirs = [ "." ]
+}
--- /dev/null
+#
+# 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.
+#
+cc = "gcc"
+cxx = "g++"
+
+toolchain("gcc") {
+ tool("cc") {
+ depfile = "{{output}}.d"
+ command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "CC {{output}}"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ }
+
+ tool("cxx") {
+ depfile = "{{output}}.d"
+ command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "CXX {{output}}"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ }
+
+ tool("alink") {
+ rspfile = "{{output}}.rsp"
+ command = "rm -f {{output}} && ar rcs {{output}} @$rspfile"
+ description = "AR {{target_output_name}}{{output_extension}}"
+ rspfile_content = "{{inputs}}"
+ outputs = [
+ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}",
+ ]
+ default_output_extension = ".a"
+
+ output_prefix = "lib"
+ }
+
+ tool("solink") {
+ soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so".
+ rspfile = soname + ".rsp"
+
+ command = "$cxx -shared {{ldflags}} -o $soname -Wl,-soname=$soname @$rspfile"
+ rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
+
+ description = "SOLINK $soname"
+
+ # Use this for {{output_extension}} expansions unless a target manually
+ # overrides it (in which case {{output_extension}} will be what the target
+ # specifies).
+ default_output_extension = ".so"
+
+ outputs = [
+ soname,
+ ]
+ link_output = soname
+ depend_output = soname
+
+ output_prefix = "lib"
+ }
+
+ tool("link") {
+ outfile = "{{target_output_name}}{{output_extension}}"
+ rspfile = "$outfile.rsp"
+ command = "$cxx {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
+ description = "LINK $outfile"
+ rspfile_content = "{{inputs}}"
+ outputs = [
+ outfile,
+ ]
+ }
+
+ tool("stamp") {
+ command = "touch {{output}}"
+ description = "STAMP {{output}}"
+ }
+
+ tool("copy") {
+ command = "cp -af {{source}} {{output}}"
+ description = "COPY {{source}} {{output}}"
+ }
+}
--- /dev/null
+#
+# 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.
+#
+
+static_library("device") {
+ sources = [
+ "src/classic/peer.c",
+ "src/controller.c"
+ ]
+
+ include_dirs = [
+ "//",
+ "//btcore/include",
+ "//gki/common",
+ "//hci/include",
+ "//include",
+ "//osi/include",
+ "//stack/include",
+ ]
+}
+
+executable("net_test_device") {
+ testonly = true
+ sources = [
+ "//osi/test/AllocationTestHarness.cpp",
+ "test/classic/peer_test.cpp",
+ ]
+
+ include_dirs = [
+ "//",
+ "//osi/include",
+ ]
+
+ deps = [
+ "//device",
+ "//btcore",
+ "//osi",
+ "//third_party/gtest:gtest_main",
+ ]
+
+ libs = [ "-lpthread", "-lrt", "-ldl" ]
+}
#define LOG_TAG "bt_classic_peer"
+#include "device/include/classic/peer.h"
+
#include <assert.h>
#include <cutils/log.h>
#include <pthread.h>
#include <stdbool.h>
#include "btcore/include/module.h"
-#include "device/include/classic/peer.h"
#include "osi/include/allocator.h"
#include "osi/include/future.h"
#include "osi/include/hash_map.h"
return NULL;
}
-const module_t classic_peer_module = {
+EXPORT_SYMBOL const module_t classic_peer_module = {
.name = CLASSIC_PEER_MODULE,
.init = init,
.start_up = NULL,
#define LOG_TAG "bt_controller"
+#include "device/include/controller.h"
+
#include <assert.h>
-#include <stdbool.h>
-#include "btcore/include/bdaddr.h"
#include "bt_types.h"
-#include "device/include/controller.h"
#include "btcore/include/event_mask.h"
-#include "osi/include/future.h"
-#include "hcimsgs.h"
-#include "hci/include/hci_layer.h"
-#include "hci/include/hci_packet_factory.h"
-#include "hci/include/hci_packet_parser.h"
#include "btcore/include/module.h"
-#include "stack/include/btm_ble_api.h"
#include "btcore/include/version.h"
+#include "hcimsgs.h"
+#include "osi/include/future.h"
+#include "stack/include/btm_ble_api.h"
const bt_event_mask_t BLE_EVENT_MASK = { "\x00\x00\x00\x00\x00\x00\x06\x7f" };
return future_new_immediate(FUTURE_SUCCESS);
}
-const module_t controller_module = {
+EXPORT_SYMBOL const module_t controller_module = {
.name = CONTROLLER_MODULE,
.init = NULL,
.start_up = start_up,
--- /dev/null
+#
+# 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.
+#
+
+source_set("sbc_decoder") {
+ sources = [
+ "decoder/srce/alloc.c",
+ "decoder/srce/bitalloc.c",
+ "decoder/srce/bitalloc-sbc.c",
+ "decoder/srce/bitstream-decode.c",
+ "decoder/srce/decoder-oina.c",
+ "decoder/srce/decoder-private.c",
+ "decoder/srce/decoder-sbc.c",
+ "decoder/srce/dequant.c",
+ "decoder/srce/framing.c",
+ "decoder/srce/framing-sbc.c",
+ "decoder/srce/oi_codec_version.c",
+ "decoder/srce/synthesis-8-generated.c",
+ "decoder/srce/synthesis-dct8.c",
+ "decoder/srce/synthesis-sbc.c",
+ ]
+
+ include_dirs = [
+ "decoder/include",
+ ]
+}
+
+source_set("sbc_encoder") {
+ sources = [
+ "encoder/srce/sbc_analysis.c",
+ "encoder/srce/sbc_dct.c",
+ "encoder/srce/sbc_dct_coeffs.c",
+ "encoder/srce/sbc_enc_bit_alloc_mono.c",
+ "encoder/srce/sbc_enc_bit_alloc_ste.c",
+ "encoder/srce/sbc_enc_coeffs.c",
+ "encoder/srce/sbc_encoder.c",
+ "encoder/srce/sbc_packing.c",
+ ]
+
+ include_dirs = [
+ "encoder/include",
+ "//include",
+ "//stack/include",
+ ]
+}
+
+static_library("sbc") {
+ deps = [
+ ":sbc_decoder",
+ ":sbc_encoder",
+ ]
+}
--- /dev/null
+#
+# 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.
+#
+
+static_library("gki") {
+ sources = [
+ "common/gki_buffer.c",
+ "ulinux/gki_ulinux.c",
+ ]
+
+ include_dirs = [
+ "common",
+ "ulinux",
+ "//",
+ "//include",
+ "//stack/include",
+ ]
+}
*/
typedef void (TIMER_CBACK)(void *p_tle);
#ifndef TIMER_PARAM_TYPE
-#define TIMER_PARAM_TYPE UINT32
+#define TIMER_PARAM_TYPE void*
#endif
/* Define a timer list entry
*/
}
// Temp module until GKI dies
-const module_t gki_module = {
+EXPORT_SYMBOL const module_t gki_module = {
.name = GKI_MODULE,
.init = init,
.start_up = NULL,
include $(BUILD_STATIC_LIBRARY)
#####################################################
+ifeq (,$(strip $(SANITIZE_TARGET)))
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := \
LOCAL_STATIC_LIBRARIES := libbt-hci libosi libcutils libbtcore
include $(BUILD_NATIVE_TEST)
+endif # SANITIZE_TARGET
--- /dev/null
+#
+# 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.
+#
+
+static_library("hci") {
+ sources = [
+ "src/btsnoop.c",
+ "src/btsnoop_mem.c",
+ "src/btsnoop_net.c",
+ "src/buffer_allocator.c",
+ "src/hci_audio.c",
+ "src/hci_hal.c",
+ "src/hci_hal_h4.c",
+ "src/hci_hal_mct.c",
+ "src/hci_inject.c",
+ "src/hci_layer.c",
+ "src/hci_packet_factory.c",
+ "src/hci_packet_parser.c",
+ "src/low_power_manager.c",
+ "src/packet_fragmenter.c",
+ "src/vendor.c",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//include",
+ "//btcore/include",
+ "//gki/common",
+ "//osi/include",
+ "//stack/include",
+ ]
+}
+
+executable("net_test_hci") {
+ testonly = true
+ sources = [
+ "//osi/test/AllocationTestHarness.cpp",
+ "//osi/test/AlarmTestHarness.cpp",
+ "test/hci_hal_h4_test.cpp",
+ "test/hci_hal_mct_test.cpp",
+ "test/hci_layer_test.cpp",
+ "test/low_power_manager_test.cpp",
+ "test/packet_fragmenter_test.cpp",
+ ]
+
+ include_dirs = [
+ "//",
+ "//include",
+ "//btcore/include",
+ "//hci/include",
+ "//osi/include",
+ "//osi/test",
+ "//stack/include",
+ ]
+
+ deps = [
+ "//hci",
+ "//osi",
+ "//btcore",
+ "//third_party/gtest:gtest_main",
+ ]
+
+ libs = [ "-lpthread", "-lrt", "-ldl" ]
+}
#pragma once
+#include <stdint.h>
+
// Audio state definitions.
typedef enum {
SCO_STATE_OFF = 0, // Audio is off.
#include <sys/time.h>
#include <unistd.h>
+#include "bt_types.h"
#include "hci/include/btsnoop.h"
#include "hci/include/btsnoop_mem.h"
-#include "bt_types.h"
#include "hci_layer.h"
#include "osi/include/log.h"
#include "stack_config.h"
return NULL;
}
-const module_t btsnoop_module = {
+EXPORT_SYMBOL const module_t btsnoop_module = {
.name = BTSNOOP_MODULE,
.init = NULL,
.start_up = start_up,
char last_log_path[PATH_MAX];
snprintf(last_log_path, PATH_MAX, "%s.%llu", log_path, btsnoop_timestamp());
if (!rename(log_path, last_log_path) && errno != ENOENT)
- LOG_ERROR("%s unable to rename '%s' to '%s': %s", __func__, log_path, last_log_path, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__, log_path, last_log_path, strerror(errno));
}
logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
if (logfile_fd == INVALID_FD) {
- LOG_ERROR("%s unable to open '%s': %s", __func__, log_path, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path, strerror(errno));
is_logging = false;
return;
}
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/types.h>
+#include <unistd.h>
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
static void safe_close_(int *fd);
static void *listen_fn_(void *context);
void btsnoop_net_open() {
listen_thread_valid_ = (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
if (!listen_thread_valid_) {
- LOG_ERROR("%s pthread_create failed: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s pthread_create failed: %s", __func__, strerror(errno));
} else {
- LOG_DEBUG("initialized");
+ LOG_DEBUG(LOG_TAG, "initialized");
}
}
listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_socket_ == -1) {
- LOG_ERROR("%s socket creation failed: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s socket creation failed: %s", __func__, strerror(errno));
goto cleanup;
}
int enable = 1;
if (setsockopt(listen_socket_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
- LOG_ERROR("%s unable to set SO_REUSEADDR: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to set SO_REUSEADDR: %s", __func__, strerror(errno));
goto cleanup;
}
addr.sin_addr.s_addr = htonl(LOCALHOST_);
addr.sin_port = htons(LISTEN_PORT_);
if (bind(listen_socket_, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
- LOG_ERROR("%s unable to bind listen socket: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to bind listen socket: %s", __func__, strerror(errno));
goto cleanup;
}
if (listen(listen_socket_, 10) == -1) {
- LOG_ERROR("%s unable to listen: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to listen: %s", __func__, strerror(errno));
goto cleanup;
}
if (errno == EINVAL || errno == EBADF) {
break;
}
- LOG_WARN("%s error accepting socket: %s", __func__, strerror(errno));
+ LOG_WARN(LOG_TAG, "%s error accepting socket: %s", __func__, strerror(errno));
continue;
}
#define LOG_TAG "bt_hci_audio"
-#include <stdint.h>
+#include "hci/include/hci_audio.h"
#include "hci/include/bt_vendor_lib.h"
-#include "hci/include/hci_audio.h"
#include "hci/include/vendor.h"
#include "osi/include/log.h"
void set_audio_state(uint16_t handle, sco_codec_t codec, sco_state_t state)
{
- LOG_INFO("%s handle:%d codec:0x%x state:%d", __func__, handle, codec, state);
+ LOG_INFO(LOG_TAG, "%s handle:%d codec:0x%x state:%d", __func__, handle, codec, state);
bt_vendor_op_audio_state_t audio_state;
#include <assert.h>
#include <errno.h>
#include <string.h>
+#include <unistd.h>
-#include "osi/include/eager_reader.h"
#include "hci_hal.h"
-#include "osi/include/osi.h"
+#include "osi/include/eager_reader.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/reactor.h"
#include "vendor.h"
}
static bool hal_open() {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
// TODO(zachoverflow): close if already open / or don't reopen (maybe at the hci layer level)
int fd_array[CH_MAX];
int number_of_ports = vendor->send_command(VENDOR_OPEN_USERIAL, &fd_array);
if (number_of_ports != 1) {
- LOG_ERROR("%s opened the wrong number of ports: got %d, expected 1.", __func__, number_of_ports);
+ LOG_ERROR(LOG_TAG, "%s opened the wrong number of ports: got %d, expected 1.", __func__, number_of_ports);
goto error;
}
uart_fd = fd_array[0];
if (uart_fd == INVALID_FD) {
- LOG_ERROR("%s unable to open the uart serial port.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to open the uart serial port.", __func__);
goto error;
}
uart_stream = eager_reader_new(uart_fd, &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_single_channel");
if (!uart_stream) {
- LOG_ERROR("%s unable to create eager reader for the uart serial port.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create eager reader for the uart serial port.", __func__);
goto error;
}
}
static void hal_close() {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
eager_reader_free(uart_stream);
vendor->send_command(VENDOR_CLOSE_USERIAL, NULL);
static size_t read_data(serial_data_type_t type, uint8_t *buffer, size_t max_size, bool block) {
if (type < DATA_TYPE_ACL || type > DATA_TYPE_EVENT) {
- LOG_ERROR("%s invalid data type: %d", __func__, type);
+ LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type);
return 0;
} else if (!stream_has_interpretation) {
- LOG_ERROR("%s with no valid stream intepretation.", __func__);
+ LOG_ERROR(LOG_TAG, "%s with no valid stream intepretation.", __func__);
return 0;
} else if (current_data_type != type) {
- LOG_ERROR("%s with different type than existing interpretation.", __func__);
+ LOG_ERROR(LOG_TAG, "%s with different type than existing interpretation.", __func__);
return 0;
}
static void packet_finished(serial_data_type_t type) {
if (!stream_has_interpretation)
- LOG_ERROR("%s with no existing stream interpretation.", __func__);
+ LOG_ERROR(LOG_TAG, "%s with no existing stream interpretation.", __func__);
else if (current_data_type != type)
- LOG_ERROR("%s with different type than existing interpretation.", __func__);
+ LOG_ERROR(LOG_TAG, "%s with different type than existing interpretation.", __func__);
stream_has_interpretation = false;
}
assert(length > 0);
if (type < DATA_TYPE_COMMAND || type > DATA_TYPE_SCO) {
- LOG_ERROR("%s invalid data type: %d", __func__, type);
+ LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type);
return 0;
}
ssize_t ret = write(uart_fd, data + transmitted_length, length);
switch (ret) {
case -1:
- LOG_ERROR("In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "In %s, error writing to the uart serial port: %s", __func__, strerror(errno));
goto done;
case 0:
// If we wrote nothing, don't loop more because we
} else {
uint8_t type_byte;
if (eager_reader_read(reader, &type_byte, 1, true) == 0) {
- LOG_ERROR("%s could not read HCI message type", __func__);
+ LOG_ERROR(LOG_TAG, "%s could not read HCI message type", __func__);
return;
}
if (type_byte < DATA_TYPE_ACL || type_byte > DATA_TYPE_EVENT) {
- LOG_ERROR("%s Unknown HCI message type. Dropping this byte 0x%x, min %x, max %x", __func__, type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
+ LOG_ERROR(LOG_TAG, "%s Unknown HCI message type. Dropping this byte 0x%x, min %x, max %x", __func__, type_byte, DATA_TYPE_ACL, DATA_TYPE_EVENT);
return;
}
#include <assert.h>
#include <errno.h>
#include <string.h>
+#include <unistd.h>
#include "bt_vendor_lib.h"
-#include "osi/include/eager_reader.h"
#include "hci_hal.h"
-#include "osi/include/osi.h"
+#include "osi/include/eager_reader.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/reactor.h"
#include "vendor.h"
}
static bool hal_open() {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
// TODO(zachoverflow): close if already open / or don't reopen (maybe at the hci layer level)
int number_of_ports = vendor->send_command(VENDOR_OPEN_USERIAL, &uart_fds);
if (number_of_ports != 2 && number_of_ports != 4) {
- LOG_ERROR("%s opened the wrong number of ports: got %d, expected 2 or 4.", __func__, number_of_ports);
+ LOG_ERROR(LOG_TAG, "%s opened the wrong number of ports: got %d, expected 2 or 4.", __func__, number_of_ports);
goto error;
}
- LOG_INFO("%s got uart fds: CMD=%d, EVT=%d, ACL_OUT=%d, ACL_IN=%d",
+ LOG_INFO(LOG_TAG, "%s got uart fds: CMD=%d, EVT=%d, ACL_OUT=%d, ACL_IN=%d",
__func__, uart_fds[CH_CMD], uart_fds[CH_EVT], uart_fds[CH_ACL_OUT], uart_fds[CH_ACL_IN]);
if (uart_fds[CH_CMD] == INVALID_FD) {
- LOG_ERROR("%s unable to open the command uart serial port.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to open the command uart serial port.", __func__);
goto error;
}
if (uart_fds[CH_EVT] == INVALID_FD) {
- LOG_ERROR("%s unable to open the event uart serial port.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to open the event uart serial port.", __func__);
goto error;
}
if (uart_fds[CH_ACL_OUT] == INVALID_FD) {
- LOG_ERROR("%s unable to open the acl-out uart serial port.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to open the acl-out uart serial port.", __func__);
goto error;
}
if (uart_fds[CH_ACL_IN] == INVALID_FD) {
- LOG_ERROR("%s unable to open the acl-in uart serial port.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to open the acl-in uart serial port.", __func__);
goto error;
}
event_stream = eager_reader_new(uart_fds[CH_EVT], &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_mct");
if (!event_stream) {
- LOG_ERROR("%s unable to create eager reader for the event uart serial port.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create eager reader for the event uart serial port.", __func__);
goto error;
}
acl_stream = eager_reader_new(uart_fds[CH_ACL_IN], &allocator_malloc, HCI_HAL_SERIAL_BUFFER_SIZE, SIZE_MAX, "hci_mct");
if (!event_stream) {
- LOG_ERROR("%s unable to create eager reader for the acl-in uart serial port.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create eager reader for the acl-in uart serial port.", __func__);
goto error;
}
}
static void hal_close() {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
eager_reader_free(event_stream);
eager_reader_free(acl_stream);
return eager_reader_read(event_stream, buffer, max_size, block);
}
- LOG_ERROR("%s invalid data type: %d", __func__, type);
+ LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type);
return 0;
}
return transmit_data_on(uart_fds[CH_CMD], data, length);
}
- LOG_ERROR("%s invalid data type: %d", __func__, type);
+ LOG_ERROR(LOG_TAG, "%s invalid data type: %d", __func__, type);
return 0;
}
ssize_t ret = write(fd, data + transmitted_length, length);
switch (ret) {
case -1:
- LOG_ERROR("In %s, error writing to the serial port with fd %d: %s", __func__, fd, strerror(errno));
+ LOG_ERROR(LOG_TAG, "In %s, error writing to the serial port with fd %d: %s", __func__, fd, strerror(errno));
return transmitted_length;
case 0:
// If we wrote nothing, don't loop more because we
#define LOG_TAG "bt_hci_inject"
+#include "hci_inject.h"
+
#include <assert.h>
#include <errno.h>
#include <string.h>
-#include "osi/include/allocator.h"
#include "bt_types.h"
#include "buffer_allocator.h"
-#include "hci_inject.h"
#include "hci_layer.h"
+#include "osi/include/allocator.h"
#include "osi/include/list.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/socket.h"
#include "osi/include/thread.h"
case HCI_PACKET_SCO_DATA:
return MSG_STACK_TO_HC_HCI_SCO;
default:
- LOG_ERROR("%s unsupported packet type: %d", __func__, packet);
+ LOG_ERROR(LOG_TAG, "%s unsupported packet type: %d", __func__, packet);
return -1;
}
}
client_t *client = (client_t *)osi_calloc(sizeof(client_t));
if (!client) {
- LOG_ERROR("%s unable to allocate memory for client.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for client.", __func__);
socket_free(socket);
return;
}
client->socket = socket;
if (!list_append(clients, client)) {
- LOG_ERROR("%s unable to add client to list.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to add client to list.", __func__);
client_free(client);
return;
}
memcpy(buf->data, buffer + 3, packet_len);
hci->transmit_downward(buf->event, buf);
} else {
- LOG_ERROR("%s dropping injected packet of length %zu", __func__, packet_len);
+ LOG_ERROR(LOG_TAG, "%s dropping injected packet of length %zu", __func__, packet_len);
}
size_t remainder = client->buffer_size - frame_len;
#define LOG_TAG "bt_hci"
+#include "hci_layer.h"
+
#include <assert.h>
-#include <cutils/properties.h>
-#include <string.h>
+#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
+#include <unistd.h>
-#include "buffer_allocator.h"
+// TODO(armansito): cutils/properties.h is only being used to pull-in runtime
+// settings on Android. Remove this conditional include once we have a generic
+// way to obtain system properties.
+#if !defined(OS_GENERIC)
+#include <cutils/properties.h>
+#endif // !defined(OS_GENERIC)
+
+#include "btcore/include/module.h"
#include "btsnoop.h"
-#include "osi/include/fixed_queue.h"
-#include "osi/include/future.h"
-#include "hcidefs.h"
-#include "hcimsgs.h"
+#include "buffer_allocator.h"
#include "hci_hal.h"
-#include "hci_internals.h"
#include "hci_inject.h"
-#include "hci_layer.h"
-#include "osi/include/list.h"
+#include "hci_internals.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
#include "low_power_manager.h"
-#include "btcore/include/module.h"
-#include "osi/include/non_repeating_timer.h"
-#include "osi/include/osi.h"
+#include "osi/include/list.h"
#include "osi/include/log.h"
-#include "packet_fragmenter.h"
+#include "osi/include/non_repeating_timer.h"
#include "osi/include/reactor.h"
+#include "packet_fragmenter.h"
#include "vendor.h"
// TODO(zachoverflow): remove this hack extern
// Module lifecycle functions
static future_t *start_up(void) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
// The host is only allowed to send at most one command initially,
// as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control)
pthread_mutex_init(&commands_pending_response_lock, NULL);
+ // TODO(armansito): cutils/properties.h is only being used to pull-in runtime
+ // settings on Android. Remove this conditional include once we have a generic
+ // way to obtain system properties. For now, always use the default timeout on
+ // non-Android builds.
+ period_ms_t startup_timeout_ms = DEFAULT_STARTUP_TIMEOUT_MS;
+
+#if !defined(OS_GENERIC)
// Grab the override startup timeout ms, if present.
- period_ms_t startup_timeout_ms;
char timeout_prop[PROPERTY_VALUE_MAX];
if (!property_get("bluetooth.enable_timeout_ms", timeout_prop, STRING_VALUE_OF(DEFAULT_STARTUP_TIMEOUT_MS))
|| (startup_timeout_ms = atoi(timeout_prop)) < 100)
startup_timeout_ms = DEFAULT_STARTUP_TIMEOUT_MS;
+#endif // !defined(OS_GENERIC)
startup_timer = non_repeating_timer_new(startup_timeout_ms, startup_timer_expired, NULL);
if (!startup_timer) {
- LOG_ERROR("%s unable to create startup timer.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create startup timer.", __func__);
goto error;
}
epilog_timer = non_repeating_timer_new(EPILOG_TIMEOUT_MS, epilog_timer_expired, NULL);
if (!epilog_timer) {
- LOG_ERROR("%s unable to create epilog timer.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create epilog timer.", __func__);
goto error;
}
command_response_timer = non_repeating_timer_new(COMMAND_PENDING_TIMEOUT, command_timed_out, NULL);
if (!command_response_timer) {
- LOG_ERROR("%s unable to create command response timer.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create command response timer.", __func__);
goto error;
}
command_queue = fixed_queue_new(SIZE_MAX);
if (!command_queue) {
- LOG_ERROR("%s unable to create pending command queue.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create pending command queue.", __func__);
goto error;
}
packet_queue = fixed_queue_new(SIZE_MAX);
if (!packet_queue) {
- LOG_ERROR("%s unable to create pending packet queue.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create pending packet queue.", __func__);
goto error;
}
thread = thread_new("hci_thread");
if (!thread) {
- LOG_ERROR("%s unable to create thread.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create thread.", __func__);
goto error;
}
commands_pending_response = list_new(NULL);
if (!commands_pending_response) {
- LOG_ERROR("%s unable to create list for commands pending response.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create list for commands pending response.", __func__);
goto error;
}
int power_state = BT_VND_PWR_OFF;
#if (defined (BT_CLEAN_TURN_ON_DISABLED) && BT_CLEAN_TURN_ON_DISABLED == TRUE)
- LOG_WARN("%s not turning off the chip before turning on.", __func__);
+ LOG_WARN(LOG_TAG, "%s not turning off the chip before turning on.", __func__);
// So apparently this hack was needed in the past because a Wingray kernel driver
// didn't handle power off commands in a powered off state correctly.
vendor->send_command(VENDOR_CHIP_POWER_CONTROL, &power_state);
startup_future = future_new();
- LOG_DEBUG("%s starting async portion", __func__);
+ LOG_DEBUG(LOG_TAG, "%s starting async portion", __func__);
thread_post(thread, event_finish_startup, NULL);
return startup_future;
error:;
}
static future_t *shut_down() {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
hci_inject->close();
return NULL;
}
-const module_t hci_module = {
+EXPORT_SYMBOL const module_t hci_module = {
.name = HCI_MODULE,
.init = NULL,
.start_up = start_up,
// Interface functions
static void do_postload() {
- LOG_DEBUG("%s posting postload work item", __func__);
+ LOG_DEBUG(LOG_TAG, "%s posting postload work item", __func__);
thread_post(thread, event_postload, NULL);
}
void *context) {
waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t));
if (!wait_entry) {
- LOG_ERROR("%s couldn't allocate space for wait entry.", __func__);
+ LOG_ERROR(LOG_TAG, "%s couldn't allocate space for wait entry.", __func__);
return;
}
if (type == MSG_STACK_TO_HC_HCI_CMD) {
// TODO(zachoverflow): eliminate this call
transmit_command((BT_HDR *)data, NULL, NULL, NULL);
- LOG_WARN("%s legacy transmit of command. Use transmit_command instead.", __func__);
+ LOG_WARN(LOG_TAG, "%s legacy transmit of command. Use transmit_command instead.", __func__);
} else {
fixed_queue_enqueue(packet_queue, data);
}
// Start up functions
static void event_finish_startup(UNUSED_ATTR void *context) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
hal->open();
vendor->send_async_command(VENDOR_CONFIGURE_FIRMWARE, NULL);
}
static void firmware_config_callback(UNUSED_ATTR bool success) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
firmware_is_configured = true;
non_repeating_timer_cancel(startup_timer);
}
static void startup_timer_expired(UNUSED_ATTR void *context) {
- LOG_ERROR("%s", __func__);
+ LOG_ERROR(LOG_TAG, "%s", __func__);
future_ready(startup_future, FUTURE_FAIL);
startup_future = NULL;
}
// Postload functions
static void event_postload(UNUSED_ATTR void *context) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
if(vendor->send_async_command(VENDOR_CONFIGURE_SCO, NULL) == -1) {
// If couldn't configure sco, we won't get the sco configuration callback
// so go pretend to do it now
}
static void sco_config_callback(UNUSED_ATTR bool success) {
- LOG_INFO("%s postload finished.", __func__);
+ LOG_INFO(LOG_TAG, "%s postload finished.", __func__);
}
// Epilog functions
}
static void epilog_finished_callback(UNUSED_ATTR bool success) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
thread_stop(thread);
}
static void epilog_timer_expired(UNUSED_ATTR void *context) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
thread_stop(thread);
}
pthread_mutex_lock(&commands_pending_response_lock);
if (list_is_empty(commands_pending_response)) {
- LOG_ERROR("%s with no commands pending response", __func__);
+ LOG_ERROR(LOG_TAG, "%s with no commands pending response", __func__);
} else {
waiting_command_t *wait_entry = list_front(commands_pending_response);
pthread_mutex_unlock(&commands_pending_response_lock);
// We shouldn't try to recover the stack from this command timeout.
// If it's caused by a software bug, fix it. If it's a hardware bug, fix it.
- LOG_ERROR("%s hci layer timeout waiting for response to a command. opcode: 0x%x", __func__, wait_entry->opcode);
+ LOG_ERROR(LOG_TAG, "%s hci layer timeout waiting for response to a command. opcode: 0x%x", __func__, wait_entry->opcode);
}
- LOG_ERROR("%s restarting the bluetooth process.", __func__);
+ LOG_ERROR(LOG_TAG, "%s restarting the bluetooth process.", __func__);
usleep(10000);
kill(getpid(), SIGKILL);
}
incoming->buffer = (BT_HDR *)buffer_allocator->alloc(buffer_size);
if (!incoming->buffer) {
- LOG_ERROR("%s error getting buffer for incoming packet of type %d and size %zd", __func__, type, buffer_size);
+ LOG_ERROR(LOG_TAG, "%s error getting buffer for incoming packet of type %d and size %zd", __func__, type, buffer_size);
// Can't read any more of this current packet, so jump out
incoming->state = incoming->bytes_remaining == 0 ? BRAND_NEW : IGNORE;
break;
break;
case FINISHED:
- LOG_ERROR("%s the state machine should not have been left in the finished state.", __func__);
+ LOG_ERROR(LOG_TAG, "%s the state machine should not have been left in the finished state.", __func__);
break;
}
wait_entry = get_waiting_command(opcode);
if (!wait_entry)
- LOG_WARN("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode);
+ LOG_WARN(LOG_TAG, "%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode);
else if (wait_entry->complete_callback)
wait_entry->complete_callback(packet, wait_entry->context);
else if (wait_entry->complete_future)
wait_entry = get_waiting_command(opcode);
if (!wait_entry)
- LOG_WARN("%s command status event with no matching command. opcode: 0x%x", __func__, opcode);
+ LOG_WARN(LOG_TAG, "%s command status event with no matching command. opcode: 0x%x", __func__, opcode);
else if (wait_entry->status_callback)
wait_entry->status_callback(status, wait_entry->command, wait_entry->context);
if (upwards_data_queue) {
fixed_queue_enqueue(upwards_data_queue, packet);
} else {
- LOG_ERROR("%s had no queue to place upwards data packet in. Dropping it on the floor.", __func__);
+ LOG_ERROR(LOG_TAG, "%s had no queue to place upwards data packet in. Dropping it on the floor.", __func__);
buffer_allocator->free(packet);
}
}
else if (event == MSG_STACK_TO_HC_HCI_CMD)
return DATA_TYPE_COMMAND;
else
- LOG_ERROR("%s invalid event type, could not translate 0x%x", __func__, event);
+ LOG_ERROR(LOG_TAG, "%s invalid event type, could not translate 0x%x", __func__, event);
return 0;
}
// there's only one instance of the hci interface.
interface.event_dispatcher = data_dispatcher_new("hci_layer");
if (!interface.event_dispatcher) {
- LOG_ERROR("%s could not create upward dispatcher.", __func__);
+ LOG_ERROR(LOG_TAG, "%s could not create upward dispatcher.", __func__);
return;
}
#define LOG_TAG "bt_hci"
+#include "hci_packet_parser.h"
+
#include <assert.h>
#include "buffer_allocator.h"
-#include "bt_types.h"
-#include "hcimsgs.h"
#include "hci_layer.h"
-#include "hci_packet_parser.h"
+#include "hcimsgs.h"
#include "osi/include/log.h"
static const command_opcode_t NO_OPCODE_CHECKING = 0;
assert(*page_number_ptr < feature_pages_count);
STREAM_TO_ARRAY(feature_pages[*page_number_ptr].as_array, stream, (int)sizeof(bt_device_features_t));
} else {
- LOG_ERROR("%s() - WARNING: READING EXTENDED FEATURES FAILED. "
+ LOG_ERROR(LOG_TAG, "%s() - WARNING: READING EXTENDED FEATURES FAILED. "
"THIS MAY INDICATE A FIRMWARE/CONTROLLER ISSUE.", __func__);
}
#define LOG_TAG "bt_low_power_manager"
+#include "low_power_manager.h"
+
#include <assert.h>
#include <stdint.h>
#include "osi/include/alarm.h"
-#include "low_power_manager.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/thread.h"
#include "vendor.h"
idle_alarm = alarm_new();
if (!idle_alarm) {
- LOG_ERROR("%s could not create idle alarm.", __func__);
+ LOG_ERROR(LOG_TAG, "%s could not create idle alarm.", __func__);
}
reset_state();
static void post_command(low_power_command_t command) {
if (command > LPM_WAKE_DEASSERT) {
- LOG_ERROR("%s unknown low power command %d", __func__, command);
+ LOG_ERROR(LOG_TAG, "%s unknown low power command %d", __func__, command);
return;
}
static void enable(bool enable) {
if (state == LPM_DISABLING) {
if (enable)
- LOG_ERROR("%s still processing prior disable request, cannot enable.", __func__);
+ LOG_ERROR(LOG_TAG, "%s still processing prior disable request, cannot enable.", __func__);
else
- LOG_WARN("%s still processing prior disable request, ignoring new request to disable.", __func__);
+ LOG_WARN(LOG_TAG, "%s still processing prior disable request, ignoring new request to disable.", __func__);
} else if (state == LPM_ENABLING) {
if (enable)
- LOG_ERROR("%s still processing prior enable request, ignoring new request to enable.", __func__);
+ LOG_ERROR(LOG_TAG, "%s still processing prior enable request, ignoring new request to enable.", __func__);
else
- LOG_WARN("%s still processing prior enable request, cannot disable.", __func__);
+ LOG_WARN(LOG_TAG, "%s still processing prior enable request, cannot disable.", __func__);
} else if (state == LPM_ENABLED && enable) {
- LOG_INFO("%s already enabled.", __func__);
+ LOG_INFO(LOG_TAG, "%s already enabled.", __func__);
} else if (state == LPM_DISABLED && !enable) {
- LOG_INFO("%s already disabled.", __func__);
+ LOG_INFO(LOG_TAG, "%s already disabled.", __func__);
} else {
uint8_t command = enable ? BT_VND_LPM_ENABLE : BT_VND_LPM_DISABLE;
state = enable ? LPM_ENABLING : LPM_DISABLING;
#define LOG_TAG "bt_hci_packet_fragmenter"
+#include "packet_fragmenter.h"
+
#include <assert.h>
#include <string.h>
#include "buffer_allocator.h"
#include "device/include/controller.h"
-#include "osi/include/hash_map.h"
#include "hci_internals.h"
-#include "hci_layer.h"
-#include "packet_fragmenter.h"
-#include "osi/include/osi.h"
#include "osi/include/hash_functions.h"
+#include "osi/include/hash_map.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#define APPLY_CONTINUATION_FLAG(handle) (((handle) & 0xCFFF) | 0x1000)
#define APPLY_START_FLAG(handle) (((handle) & 0xCFFF) | 0x2000)
if (boundary_flag == START_PACKET_BOUNDARY) {
if (partial_packet) {
- LOG_WARN("%s found unfinished packet for handle with start packet. Dropping old.", __func__);
+ LOG_WARN(LOG_TAG, "%s found unfinished packet for handle with start packet. Dropping old.", __func__);
hash_map_erase(partial_packets, (void *)(uintptr_t)handle);
buffer_allocator->free(partial_packet);
uint16_t full_length = l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE;
if (full_length <= packet->len) {
if (full_length < packet->len)
- LOG_WARN("%s found l2cap full length %d less than the hci length %d.", __func__, l2cap_length, packet->len);
+ LOG_WARN(LOG_TAG, "%s found l2cap full length %d less than the hci length %d.", __func__, l2cap_length, packet->len);
callbacks->reassembled(packet);
return;
buffer_allocator->free(packet);
} else {
if (!partial_packet) {
- LOG_WARN("%s got continuation for unknown packet. Dropping it.", __func__);
+ LOG_WARN(LOG_TAG, "%s got continuation for unknown packet. Dropping it.", __func__);
buffer_allocator->free(packet);
return;
}
packet->offset = HCI_ACL_PREAMBLE_SIZE;
uint16_t projected_offset = partial_packet->offset + (packet->len - HCI_ACL_PREAMBLE_SIZE);
if (projected_offset > partial_packet->len) { // len stores the expected length
- LOG_WARN("%s got packet which would exceed expected length of %d. Truncating.", __func__, partial_packet->len);
+ LOG_WARN(LOG_TAG, "%s got packet which would exceed expected length of %d. Truncating.", __func__, partial_packet->len);
packet->len = partial_packet->len - partial_packet->offset;
projected_offset = partial_packet->len;
}
#define LOG_TAG "bt_vendor"
+#include "vendor.h"
+
#include <assert.h>
#include <dlfcn.h>
#include "buffer_allocator.h"
-#include "bt_vendor_lib.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
-#include "vendor.h"
+#include "osi/include/osi.h"
#define LAST_VENDOR_OPCODE_VALUE VENDOR_DO_EPILOG
lib_handle = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
if (!lib_handle) {
- LOG_ERROR("%s unable to open %s: %s", __func__, VENDOR_LIBRARY_NAME, dlerror());
+ LOG_ERROR(LOG_TAG, "%s unable to open %s: %s", __func__, VENDOR_LIBRARY_NAME, dlerror());
goto error;
}
lib_interface = (bt_vendor_interface_t *)dlsym(lib_handle, VENDOR_LIBRARY_SYMBOL_NAME);
if (!lib_interface) {
- LOG_ERROR("%s unable to find symbol %s in %s: %s", __func__, VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
+ LOG_ERROR(LOG_TAG, "%s unable to find symbol %s in %s: %s", __func__, VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
goto error;
}
- LOG_INFO("alloc value %p", lib_callbacks.alloc);
+ LOG_INFO(LOG_TAG, "alloc value %p", lib_callbacks.alloc);
int status = lib_interface->init(&lib_callbacks, (unsigned char *)local_bdaddr);
if (status) {
- LOG_ERROR("%s unable to initialize vendor library: %d", __func__, status);
+ LOG_ERROR(LOG_TAG, "%s unable to initialize vendor library: %d", __func__, status);
goto error;
}
// Called back from vendor library when the firmware configuration
// completes.
static void firmware_config_cb(bt_vendor_op_result_t result) {
- LOG_INFO("firmware callback");
+ LOG_INFO(LOG_TAG, "firmware callback");
vendor_cb callback = callbacks[VENDOR_CONFIGURE_FIRMWARE];
assert(callback != NULL);
callback(result == BT_VND_OP_RESULT_SUCCESS);
// SCO configuration request. This should only happen during the
// postload process.
static void sco_config_cb(bt_vendor_op_result_t result) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
vendor_cb callback = callbacks[VENDOR_CONFIGURE_SCO];
assert(callback != NULL);
callback(result == BT_VND_OP_RESULT_SUCCESS);
// Called back from vendor library to indicate status of previous
// LPM enable/disable request.
static void low_power_mode_cb(bt_vendor_op_result_t result) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
vendor_cb callback = callbacks[VENDOR_SET_LPM_MODE];
assert(callback != NULL);
callback(result == BT_VND_OP_RESULT_SUCCESS);
{
uint8_t status = (result == BT_VND_OP_RESULT_SUCCESS) ? 0 : 1;
- LOG_INFO("sco_audiostate_cb(status: %d)",status);
+ LOG_INFO(LOG_TAG, "sco_audiostate_cb(status: %d)",status);
}
// Called by vendor library when it needs an HCI buffer.
// completed. It is safe to call vendor_interface->cleanup() after
// this callback has been received.
static void epilog_cb(bt_vendor_op_result_t result) {
- LOG_INFO("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s", __func__);
vendor_cb callback = callbacks[VENDOR_DO_EPILOG];
assert(callback != NULL);
callback(result == BT_VND_OP_RESULT_SUCCESS);
#ifndef TIMER_PARAM_TYPE
-#define TIMER_PARAM_TYPE UINT32
+#define TIMER_PARAM_TYPE void*
#endif
/******************************************************************************
libcutils \
libdl \
liblog \
- libpower \
libz
LOCAL_STATIC_LIBRARIES := \
--- /dev/null
+#
+# 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.
+#
+
+shared_library("bluetooth.default") {
+ # HAL layer
+ sources = [
+ "//btif/src/bluetooth.c",
+ ]
+
+ # platform specific
+ sources += [
+ "bte_main.c",
+ "bte_init.c",
+ "bte_logmsg.c",
+ "bte_conf.c",
+ "stack_config.c",
+ ]
+
+ include_dirs = [
+ "//",
+ "//bta/include",
+ "//bta/sys",
+ "//bta/dm",
+ "//btcore/include",
+ "//osi/include",
+ "//gki/common",
+ "//gki/ulinux",
+ "//include",
+ "//stack/include",
+ "//stack/l2cap",
+ "//stack/a2dp",
+ "//stack/btm",
+ "//stack/avdt",
+ "//hci",
+ "//hci/include",
+ "//udrv/include",
+ "//btif/include",
+ "//btif/co",
+ "//hci/includ",
+ "//vnd/include",
+ "//brcm/include",
+ "//embdrv/sbc/encoder/include",
+ "//embdrv/sbc/decoder/include",
+ "//audio_a2dp_hw",
+ "//utils/include",
+ ]
+
+ deps = [
+ "//audio_a2dp_hw:audio.a2dp.default",
+ "//bta",
+ "//btcore",
+ "//btif",
+ "//device",
+ "//embdrv/sbc",
+ "//gki",
+ "//hci",
+ "//osi",
+ "//stack",
+ "//third_party/tinyxml2",
+ "//udrv",
+ "//utils",
+ ]
+
+ libs = [ "-ldl", "-lpthread", "-lresolv", "-lrt", "-lz" ]
+}
{
assert(path != NULL);
- LOG_INFO("%s attempt to load ble stack conf from %s", __func__, path);
+ LOG_INFO(LOG_TAG, "%s attempt to load ble stack conf from %s", __func__, path);
config_t *config = config_new(path);
if (!config) {
- LOG_INFO("%s file >%s< not found", __func__, path);
+ LOG_INFO(LOG_TAG, "%s file >%s< not found", __func__, path);
return;
}
if(*ble_adv_tx_power) {
sscanf(ble_adv_tx_power, "%d,%d,%d,%d,%d", btm_ble_tx_power, btm_ble_tx_power + 1, btm_ble_tx_power + 2,
btm_ble_tx_power + 3, btm_ble_tx_power + 4);
- LOG_INFO("loaded btm_ble_tx_power: %d, %d, %d, %d, %d", (char)btm_ble_tx_power[0], (char)btm_ble_tx_power[1],
+ LOG_INFO(LOG_TAG, "loaded btm_ble_tx_power: %d, %d, %d, %d, %d", (char)btm_ble_tx_power[0], (char)btm_ble_tx_power[1],
btm_ble_tx_power[2], btm_ble_tx_power[3], btm_ble_tx_power[4]);
}
config_free(config);
config_t *config = config_new(p_path);
if (!config) {
- LOG_ERROR("%s unable to load DID config '%s'.", __func__, p_path);
+ LOG_ERROR(LOG_TAG, "%s unable to load DID config '%s'.", __func__, p_path);
return;
}
snprintf(section_name, sizeof(section_name), "DID%d", i);
if (!config_has_section(config, section_name)) {
- LOG_DEBUG("%s no section named %s.", __func__, section_name);
+ LOG_DEBUG(LOG_TAG, "%s no section named %s.", __func__, section_name);
break;
}
if (record.vendor_id_source != DI_VENDOR_ID_SOURCE_BTSIG &&
record.vendor_id_source != DI_VENDOR_ID_SOURCE_USBIF) {
- LOG_ERROR("%s invalid vendor id source %d; ignoring DID record %d.", __func__, record.vendor_id_source, i);
+ LOG_ERROR(LOG_TAG, "%s invalid vendor id source %d; ignoring DID record %d.", __func__, record.vendor_id_source, i);
continue;
}
- LOG_DEBUG("Device ID record %d : %s", i, (record.primary_record ? "primary" : "not primary"));
- LOG_DEBUG(" vendorId = %04x", record.vendor);
- LOG_DEBUG(" vendorIdSource = %04x", record.vendor_id_source);
- LOG_DEBUG(" product = %04x", record.product);
- LOG_DEBUG(" version = %04x", record.version);
- LOG_DEBUG(" clientExecutableURL = %s", record.client_executable_url);
- LOG_DEBUG(" serviceDescription = %s", record.service_description);
- LOG_DEBUG(" documentationURL = %s", record.documentation_url);
+ LOG_DEBUG(LOG_TAG, "Device ID record %d : %s", i, (record.primary_record ? "primary" : "not primary"));
+ LOG_DEBUG(LOG_TAG, " vendorId = %04x", record.vendor);
+ LOG_DEBUG(LOG_TAG, " vendorIdSource = %04x", record.vendor_id_source);
+ LOG_DEBUG(LOG_TAG, " product = %04x", record.product);
+ LOG_DEBUG(LOG_TAG, " version = %04x", record.version);
+ LOG_DEBUG(LOG_TAG, " clientExecutableURL = %s", record.client_executable_url);
+ LOG_DEBUG(LOG_TAG, " serviceDescription = %s", record.service_description);
+ LOG_DEBUG(LOG_TAG, " documentationURL = %s", record.documentation_url);
uint32_t record_handle;
tBTA_STATUS status = BTA_DmSetLocalDiRecord(&record, &record_handle);
if (status != BTA_SUCCESS) {
- LOG_ERROR("%s unable to set device ID record %d: error %d.", __func__, i, status);
+ LOG_ERROR(LOG_TAG, "%s unable to set device ID record %d: error %d.", __func__, i, status);
}
}
*
******************************************************************************/
+#define LOG_TAG "bt_bte"
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
-#include "bte.h"
+#include "avrc_api.h"
#include "bta_api.h"
+#include "bte.h"
+#include "btm_api.h"
#include "btu.h"
-#include "osi/include/config.h"
+#include "gap_api.h"
#include "gki.h"
#include "l2c_api.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
#include "osi/include/log.h"
+#include "port_api.h"
+#include "sdp_api.h"
#include "stack_config.h"
-#include "port_api.h"
-#if (AVDT_INCLUDED==TRUE)
-#include "avdt_api.h"
-#endif
-#include "avrc_api.h"
#if (AVDT_INCLUDED==TRUE)
#include "avdt_api.h"
#endif
#if (BNEP_INCLUDED==TRUE)
#include "bnep_api.h"
#endif
-#include "btm_api.h"
-#include "gap_api.h"
#if (PAN_INCLUDED==TRUE)
#include "pan_api.h"
#endif
-#include "sdp_api.h"
-
#if (BLE_INCLUDED==TRUE)
#include "gatt_api.h"
#include "smp_api.h"
#endif
-#define LOGI0(t,s) __android_log_write(ANDROID_LOG_INFO, t, s)
-#define LOGD0(t,s) __android_log_write(ANDROID_LOG_DEBUG, t, s)
-#define LOGW0(t,s) __android_log_write(ANDROID_LOG_WARN, t, s)
-#define LOGE0(t,s) __android_log_write(ANDROID_LOG_ERROR, t, s)
-
#ifndef DEFAULT_CONF_TRACE_LEVEL
#define DEFAULT_CONF_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
#endif
switch ( TRACE_GET_TYPE(trace_set_mask) ) {
case TRACE_TYPE_ERROR:
- LOGE0(bt_layer_tags[trace_layer], buffer);
+ LOG_ERROR(bt_layer_tags[trace_layer], "%s", buffer);
break;
case TRACE_TYPE_WARNING:
- LOGW0(bt_layer_tags[trace_layer], buffer);
+ LOG_WARN(bt_layer_tags[trace_layer], "%s", buffer);
break;
case TRACE_TYPE_API:
case TRACE_TYPE_EVENT:
- LOGI0(bt_layer_tags[trace_layer], buffer);
+ LOG_INFO(bt_layer_tags[trace_layer], "%s", buffer);
break;
case TRACE_TYPE_DEBUG:
- LOGD0(bt_layer_tags[trace_layer], buffer);
+ LOG_DEBUG(bt_layer_tags[trace_layer], "%s", buffer);
break;
default:
- LOGE0(bt_layer_tags[trace_layer], buffer); /* we should never get this */
+ LOG_ERROR(bt_layer_tags[trace_layer], "%s", buffer); /* we should never get this */
break;
}
}
assert(config != NULL);
for (tBTTRC_FUNC_MAP *functions = &bttrc_set_level_map[0]; functions->trc_name; ++functions) {
- LOG_INFO("BTE_InitTraceLevels -- %s", functions->trc_name);
+ LOG_INFO(LOG_TAG, "BTE_InitTraceLevels -- %s", functions->trc_name);
int value = config_get_int(config, CONFIG_DEFAULT_SECTION, functions->trc_name, -1);
if (value != -1)
functions->trace_level = value;
static future_t *init(void) {
const stack_config_t *stack_config = stack_config_get_interface();
if (!stack_config->get_trace_config_enabled()) {
- LOG_INFO("[bttrc] using compile default trace settings");
+ LOG_INFO(LOG_TAG, "using compile default trace settings");
return NULL;
}
return NULL;
}
-const module_t bte_logmsg_module = {
+EXPORT_SYMBOL const module_t bte_logmsg_module = {
.name = BTE_LOGMSG_MODULE,
.init = init,
.start_up = NULL,
#define LOG_TAG "bt_main"
#include <assert.h>
-#include <cutils/properties.h>
#include <fcntl.h>
-#include <hardware/bluetooth.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
-#include "osi/include/alarm.h"
-#include "bta_api.h"
+#include <hardware/bluetooth.h>
+
#include "bt_hci_bdroid.h"
-#include "bte.h"
-#include "btif_common.h"
-#include "btu.h"
-#include "btsnoop.h"
#include "bt_utils.h"
+#include "bta_api.h"
#include "btcore/include/counter.h"
#include "btcore/include/module.h"
+#include "bte.h"
+#include "btif_common.h"
+#include "btsnoop.h"
+#include "btu.h"
+#include "gki.h"
+#include "hci_layer.h"
+#include "osi/include/alarm.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/future.h"
-#include "gki.h"
#include "osi/include/hash_functions.h"
#include "osi/include/hash_map.h"
-#include "hci_layer.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
-#include "stack_config.h"
+#include "osi/include/osi.h"
#include "osi/include/thread.h"
+#include "stack_config.h"
/*******************************************************************************
** Constants & Macros
/* 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
hci = hci_layer_get_interface();
if (!hci)
- LOG_ERROR("%s could not get hci layer interface.", __func__);
+ LOG_ERROR(LOG_TAG, "%s could not get hci layer interface.", __func__);
btu_hci_msg_queue = fixed_queue_new(SIZE_MAX);
if (btu_hci_msg_queue == NULL) {
- LOG_ERROR("%s unable to allocate hci message queue.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate hci message queue.", __func__);
return;
}
**
** Function bte_main_lpm_allow_bt_device_sleep
**
-** Description BTE MAIN API - Allow BT controller goest to sleep
+** Description BTE MAIN API - Allow the BT controller to go to sleep
**
** Returns None
**
#define LOG_TAG "bt_stack_config"
+#include "stack_config.h"
+
#include <assert.h>
#include "osi/include/future.h"
-#include "stack_config.h"
#include "osi/include/log.h"
const char *BTSNOOP_LOG_PATH_KEY = "BtSnoopFileName";
// 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("%s attempt to load stack conf from %s", __func__, path);
+ LOG_INFO(LOG_TAG, "%s attempt to load stack conf from %s", __func__, path);
config = config_new(path);
if (!config) {
- LOG_INFO("%s file >%s< not found", __func__, path);
+ LOG_INFO(LOG_TAG, "%s file >%s< not found", __func__, path);
return future_new_immediate(FUTURE_FAIL);
}
return future_new_immediate(FUTURE_SUCCESS);
}
-const module_t stack_config_module = {
+EXPORT_SYMBOL const module_t stack_config_module = {
.name = STACK_CONFIG_MODULE,
.init = init,
.start_up = NULL,
LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# osi/include/atomic.h depends on gcc atomic functions
-LOCAL_CLANG := false
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/include \
- $(LOCAL_PATH)/..
+# Common variables
+# ========================================================
-LOCAL_SRC_FILES := \
+# TODO(mcchou): Remove socket_utils sources after platform specific
+# dependencies are abstracted.
+btosiCommonSrc := \
./src/alarm.c \
./src/allocation_tracker.c \
./src/allocator.c \
./src/array.c \
./src/buffer.c \
+ ./src/compat.c \
./src/config.c \
./src/data_dispatcher.c \
./src/eager_reader.c \
./src/future.c \
./src/hash_functions.c \
./src/hash_map.c \
+ ./src/hash_map_utils.c \
./src/list.c \
./src/non_repeating_timer.c \
./src/reactor.c \
./src/ringbuffer.c \
./src/semaphore.c \
./src/socket.c \
+ ./src/socket_utils/socket_local_client.c \
+ ./src/socket_utils/socket_local_server.c \
./src/thread.c
-LOCAL_CFLAGS := -std=c99 -Wall -Werror -UNDEBUG
-# Many .h files have redefined typedefs
-LOCAL_CLANG_CFLAGS += -Wno-error=typedef-redefinition
-LOCAL_MODULE := libosi
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := libc liblog
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-
-include $(BUILD_STATIC_LIBRARY)
-
-#####################################################
-
-include $(CLEAR_VARS)
-
-# osi/include/atomic.h depends on gcc atomic functions
-LOCAL_CLANG := false
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/include \
- $(LOCAL_PATH)/..
-
-LOCAL_SRC_FILES := \
+btosiCommonTestSrc := \
./test/AlarmTestHarness.cpp \
./test/AllocationTestHarness.cpp \
./test/alarm_test.cpp \
./test/allocation_tracker_test.cpp \
+ ./test/allocator_test.cpp \
./test/array_test.cpp \
- ./test/atomic_test.cpp \
./test/config_test.cpp \
./test/data_dispatcher_test.cpp \
./test/eager_reader_test.cpp \
./test/future_test.cpp \
./test/hash_map_test.cpp \
+ ./test/hash_map_utils_test.cpp \
./test/list_test.cpp \
./test/reactor_test.cpp \
./test/ringbuffer_test.cpp \
./test/thread_test.cpp
+btosiCommonIncludes := \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/.. \
+ $(LOCAL_PATH)/../utils/include
+
+btosiCommonCFlags := -std=c99 -Wall -Werror -UNDEBUG -fvisibility=hidden
+
+# libosi static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := $(btosiCommonIncludes)
+LOCAL_SRC_FILES := $(btosiCommonSrc)
+LOCAL_CFLAGS := $(btosiCommonCFlags)
+# Many .h files have redefined typedefs
+LOCAL_CLANG_CFLAGS += -Wno-error=typedef-redefinition
+LOCAL_MODULE := libosi
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libc liblog
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+include $(BUILD_STATIC_LIBRARY)
+
+# libosi static library for host
+# ========================================================
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := $(btosiCommonIncludes)
+LOCAL_SRC_FILES := $(btosiCommonSrc)
+# TODO(armansito): Setting _GNU_SOURCE isn't very platform-independent but
+# should be compatible for a Linux host OS. We should figure out what to do for
+# a non-Linux host OS.
+LOCAL_CFLAGS := \
+ $(btosiCommonCFlags) \
+ -D_GNU_SOURCE
+# Many .h files have redefined typedefs
+LOCAL_CLANG_CFLAGS += -Wno-error=typedef-redefinition
+LOCAL_MODULE := libosi-host
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+include $(BUILD_HOST_STATIC_LIBRARY)
+endif
+
+# Note: It's good to get the tests compiled both for the host and the target so
+# we get to test with both Bionic libc and glibc
+
+# libosi unit tests for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := $(btosiCommonIncludes)
+LOCAL_SRC_FILES := $(btosiCommonTestSrc)
LOCAL_CFLAGS := -Wall -UNDEBUG
LOCAL_MODULE := net_test_osi
LOCAL_MODULE_TAGS := tests
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_STATIC_LIBRARIES := libosi
-
include $(BUILD_NATIVE_TEST)
+
+# libosi unit tests for host
+# ========================================================
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := $(btosiCommonIncludes)
+LOCAL_SRC_FILES := $(btosiCommonTestSrc)
+LOCAL_CFLAGS := -Wall -UNDEBUG
+LOCAL_LDLIBS := -lrt -lpthread
+LOCAL_MODULE := net_test_osi
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_STATIC_LIBRARIES := libosi-host
+include $(BUILD_HOST_NATIVE_TEST)
+endif
--- /dev/null
+#
+# 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.
+#
+
+static_library("osi") {
+ sources = [
+ "src/alarm.c",
+ "src/allocation_tracker.c",
+ "src/allocator.c",
+ "src/array.c",
+ "src/buffer.c",
+ "src/compat.c",
+ "src/config.c",
+ "src/data_dispatcher.c",
+ "src/eager_reader.c",
+ "src/fixed_queue.c",
+ "src/future.c",
+ "src/hash_functions.c",
+ "src/hash_map.c",
+ "src/hash_map_utils.c",
+ "src/list.c",
+ "src/non_repeating_timer.c",
+ "src/reactor.c",
+ "src/ringbuffer.c",
+ "src/semaphore.c",
+ "src/socket.c",
+
+ # TODO(mcchou): Remove these sources after platform specific
+ # dependencies are abstracted.
+ "src/socket_utils/socket_local_client.c",
+ "src/socket_utils/socket_local_server.c",
+
+ "src/thread.c",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//utils/include",
+ ]
+}
+
+executable("net_test_osi") {
+ testonly = true
+ sources = [
+ "test/AlarmTestHarness.cpp",
+ "test/AllocationTestHarness.cpp",
+ "test/alarm_test.cpp",
+ "test/allocation_tracker_test.cpp",
+ "test/allocator_test.cpp",
+ "test/array_test.cpp",
+ "test/config_test.cpp",
+ "test/data_dispatcher_test.cpp",
+ "test/eager_reader_test.cpp",
+ "test/future_test.cpp",
+ "test/hash_map_test.cpp",
+ "test/hash_map_utils_test.cpp",
+ "test/list_test.cpp",
+ "test/reactor_test.cpp",
+ "test/ringbuffer_test.cpp",
+ "test/thread_test.cpp",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ ]
+
+ deps = [
+ "//osi",
+ "//third_party/gtest:gtest_main",
+ ]
+
+ libs = [ "-lpthread", "-lrt" ]
+}
extern const allocator_t allocator_calloc;
char *osi_strdup(const char *str);
+char *osi_strndup(const char *str, size_t len);
void *osi_malloc(size_t size);
void *osi_calloc(size_t size);
+++ /dev/null
-/******************************************************************************
- *
- * 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 <stdint.h>
-
-// Set of atomic operations to work on data structures.
-// The atomic type data should only be manipulated by these functions.
-// This uses the gcc built in functions.
-// gcc doc section 6.50 "Built-in functions for memory model aware atomic operations"
-//
-// Data types:
-// atomic_<name>_t
-//
-// e.g.
-// atomic_s32_t for a signed 32 bit integer.
-// atomic_u32_t for an unsigned 32 bit integer.
-//
-// Functions:
-// atomic_<operation>_<name>(atomic_t *, ...)
-//
-// e.g.
-// uint32_t atomic_dec_prefix_u32(volatile atomic_u32_t *atomic)
-//
-// The prefix/postfix classification corresponds which value is returned
-// from the function call, the old or the new one.
-
-#if defined(GCC_VERSION) && GCC_VERSION < 40700
-#warning "Atomics not supported"
-#endif
-
-#define ATOMIC_TYPE(name, type) \
- struct atomic_##name { \
- type _val; \
-}; \
-typedef struct atomic_##name atomic_##name##_t;
-
-#define ATOMIC_STORE(name, type, sz) \
-static inline void atomic_store_##name(volatile atomic_##name##_t *atomic, type val) { \
- __atomic_store_##sz(&atomic->_val, val, __ATOMIC_SEQ_CST); \
-}
-
-#define ATOMIC_LOAD(name, type, sz) \
-static inline type atomic_load_##name(volatile atomic_##name##_t *atomic) { \
- return __atomic_load_##sz(&atomic->_val, __ATOMIC_SEQ_CST); \
-}
-
-// Returns value after operation, e.g. new value
-#define ATOMIC_INC_PREFIX(name, type, sz) \
-static inline type atomic_inc_prefix_##name(volatile atomic_##name##_t *atomic) { \
- return __atomic_add_fetch_##sz(atomic, 1, __ATOMIC_SEQ_CST); \
-}
-
-// Returns value after operation, e.g. new value
-#define ATOMIC_DEC_PREFIX(name, type, sz) \
-static inline type atomic_dec_prefix_##name(volatile atomic_##name##_t *atomic) { \
- return __atomic_sub_fetch_##sz(atomic, 1, __ATOMIC_SEQ_CST); \
-}
-
-// Returns value before operation, e.g. old value
-#define ATOMIC_INC_POSTFIX(name, type, sz) \
-static inline type atomic_inc_postfix_##name(volatile atomic_##name##_t *atomic) { \
- return __atomic_fetch_add_##sz(atomic, 1, __ATOMIC_SEQ_CST); \
-}
-
-// Returns value before operation, e.g. old value
-#define ATOMIC_DEC_POSTFIX(name, type, sz) \
-static inline type atomic_dec_postfix_##name(volatile atomic_##name##_t *atomic) { \
- return __atomic_fetch_sub_##sz(atomic, 1, __ATOMIC_SEQ_CST); \
-}
-
-// Returns value after operation, e.g. new value
-#define ATOMIC_ADD(name, type, sz) \
-static inline type atomic_add_##name(volatile atomic_##name##_t *atomic, type val) { \
- return __atomic_add_fetch_##sz(atomic, val, __ATOMIC_SEQ_CST); \
-}
-
-// Returns value after operation, e.g. new value
-#define ATOMIC_SUB(name, type, sz) \
-static inline type atomic_sub_##name(volatile atomic_##name##_t *atomic, type val) { \
- return __atomic_sub_fetch_##sz(atomic, val, __ATOMIC_SEQ_CST); \
-}
-
-#define ATOMIC_MAKE(name, type, sz) \
- ATOMIC_TYPE(name, type) \
- ATOMIC_STORE(name, type, sz) \
- ATOMIC_LOAD(name, type, sz) \
- ATOMIC_INC_PREFIX(name, type, sz) \
- ATOMIC_DEC_PREFIX(name, type, sz) \
- ATOMIC_INC_POSTFIX(name, type, sz) \
- ATOMIC_DEC_POSTFIX(name, type, sz) \
- ATOMIC_ADD(name, type, sz) \
- ATOMIC_SUB(name, type, sz)
-
-ATOMIC_MAKE(s32, int32_t, 4)
-ATOMIC_MAKE(u32, uint32_t, 4)
-ATOMIC_MAKE(s64, int64_t, 8)
-ATOMIC_MAKE(u64, uint64_t, 8)
#pragma once
#include <stdbool.h>
+#include <stdlib.h>
struct fixed_queue_t;
typedef struct fixed_queue_t fixed_queue_t;
#pragma once
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
struct hash_map_t;
typedef bool (*key_equality_fn)(const void *x, const void *y);
-typedef void (*key_free_fn)(void *data);
+typedef void (*key_free_fn)(void *key);
typedef void (*data_free_fn)(void *data);
// Returns a new, empty hash_map. Returns NULL if not enough memory could be allocated
--- /dev/null
+/******************************************************************************
+ *
+ * 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
+
+#include "osi/include/hash_map.h"
+
+// Creates a hash map based on the |params| string containing key and value
+// pairs. Pairs are expected in the form "key=value" separated by the ';'
+// character. Both ';' and '=' characters are invalid in keys or values.
+// |params| cannot be NULL, is not modified and is owned by the caller.
+// Examples:
+// "key0=value10;key1=value1;" -> map: [key0]="value0" [key1]="value1"
+// "key0=;key1=value1;" -> map: [key0]="" [key1]="value1"
+// "=value0;key1=value1;" -> map: [key1]="value1"
+// A new hash map or NULL is returned and is owned by the caller.
+hash_map_t *hash_map_utils_new_from_string_params(const char *params);
+
+// Dumps the contents of the hash_map to the log for debugging purposes.
+// If |map| is not NULL, all entries of |map| will be dumped, otherwise nothing
+// will be dumped. Note that this function does not take the ownership of |map|.
+void hash_map_utils_dump_string_keys_string_values(hash_map_t *map);
#pragma once
+/*
+ * TODO(armansito): Work-around until we figure out a way to generate logs in a
+ * platform-independent manner.
+ */
+#if defined(OS_GENERIC)
+
+/* syslog didn't work well here since we would be redefining LOG_DEBUG. */
+#include <stdio.h>
+
+#define LOGWRAPPER(tag, fmt, args...) fprintf(stderr, "%s: " fmt "\n", tag, ## args)
+
+#define LOG_VERBOSE(...) LOGWRAPPER(__VA_ARGS__)
+#define LOG_DEBUG(...) LOGWRAPPER(__VA_ARGS__)
+#define LOG_INFO(...) LOGWRAPPER(__VA_ARGS__)
+#define LOG_WARN(...) LOGWRAPPER(__VA_ARGS__)
+#define LOG_ERROR(...) LOGWRAPPER(__VA_ARGS__)
+
+#else /* !defined(OS_GENERIC) */
+
#include <cutils/log.h>
-#define LOG_VERBOSE(...) ALOGV(__VA_ARGS__)
-#define LOG_DEBUG(...) ALOGD(__VA_ARGS__)
-#define LOG_INFO(...) ALOGI(__VA_ARGS__)
-#define LOG_WARN(...) ALOGW(__VA_ARGS__)
-#define LOG_ERROR(...) ALOGE(__VA_ARGS__)
+#if LOG_NDEBUG
+#define LOG_VERBOSE(...) ((void)0)
+#else // LOG_NDEBUG
+#define LOG_VERBOSE(tag, fmt, args...) ALOG(LOG_VERBOSE, tag, fmt, ## args)
+#endif // !LOG_NDEBUG
+#define LOG_DEBUG(tag, fmt, args...) ALOG(LOG_DEBUG, tag, fmt, ## args )
+#define LOG_INFO(tag, fmt, args...) ALOG(LOG_INFO, tag, fmt, ## args)
+#define LOG_WARN(tag, fmt, args...) ALOG(LOG_WARN, tag, fmt, ## args)
+#define LOG_ERROR(tag, fmt, args...) ALOG(LOG_ERROR, tag, fmt, ## args)
+
+#endif /* defined(OS_GENERIC) */
#define DUMMY_COUNTER(c) CONCAT(__osi_dummy_, c)
#define DUMMY_PTR DUMMY_COUNTER(__COUNTER__)
+// base/macros.h defines a COMPILE_ASSERT macro to the C++11 keyword
+// "static_assert" (it undef's COMPILE_ASSERT before redefining it).
+// C++ code that includes base and osi/include/osi.h can thus easily default to
+// the definition from libbase but we should check here to avoid compile errors.
+#ifndef COMPILE_ASSERT
#define COMPILE_ASSERT(x) char * DUMMY_PTR = !(x)
+#endif // COMPILE_ASSERT
typedef uint32_t timeout_t;
+
+// Macros for safe integer to pointer conversion. In the C language, data is
+// commonly cast to opaque pointer containers and back for generic parameter
+// passing in callbacks. These macros should be used sparingly in new code
+// (never in C++ code). Whenever integers need to be passed as a pointer, use
+// these macros.
+#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p)))
+#define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u)))
+
+#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
+#define INT_TO_PTR(i) ((void *) ((intptr_t) (i)))
--- /dev/null
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * 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
+
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+
+/*
+ * Set up a given sockaddr_un, to have it refer to the given
+ * name in the given namespace. The namespace must be one
+ * of <code>ANDROID_SOCKET_NAMESPACE_ABSTRACT</code>,
+ * <code>ANDROID_SOCKET_NAMESPACE_RESERVED</code>, or
+ * <code>ANDROID_SOCKET_NAMESPACE_FILESYSTEM</code>. Upon success,
+ * the pointed at sockaddr_un is filled in and the pointed at
+ * socklen_t is set to indicate the final length. This function
+ * will fail if the namespace is invalid (not one of the indicated
+ * constants) or if the name is too long.
+ *
+ * @return 0 on success or -1 on failure
+ */
+int osi_socket_make_sockaddr_un(const char *name, int namespaceId,
+ struct sockaddr_un *p_addr, socklen_t *alen);
--- /dev/null
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * 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 <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
+#define ANDROID_SOCKET_DIR "/dev/socket"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * osi_android_get_control_socket - simple helper function to get the file
+ * descriptor of our init-managed Unix domain socket. `name' is the name of the
+ * socket, as given in init.rc. Returns -1 on error.
+ *
+ * This is inline and not in libcutils proper because we want to use this in
+ * third-party daemons with minimal modification.
+ */
+static inline int osi_android_get_control_socket(const char *name) {
+ char key[64];
+ snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
+
+ const char *val = getenv(key);
+ if (!val) {
+ return -1;
+ }
+
+ errno = 0;
+ int fd = strtol(val, NULL, 10);
+ if (errno) {
+ return -1;
+ }
+
+ return fd;
+}
+
+/*
+ * See also android.os.LocalSocketAddress.Namespace
+ */
+// Linux "abstract" (non-filesystem) namespace
+#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
+// Android "reserved" (/dev/socket) namespace
+#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
+// Normal filesystem namespace
+#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2
+
+extern int osi_socket_local_server(const char *name, int namespaceId, int type);
+extern int osi_socket_local_server_bind(int s, const char *name,
+ int namespaceId);
+extern int osi_socket_local_client_connect(int fd, const char *name,
+ int namespaceId, int type);
+extern int osi_socket_local_client(const char *name, int namespaceId, int type);
+
+#ifdef __cplusplus
+}
+#endif
#define LOG_TAG "bt_osi_alarm"
+#include "osi/include/alarm.h"
+
#include <assert.h>
#include <errno.h>
-#include <hardware/bluetooth.h>
#include <inttypes.h>
#include <malloc.h>
-#include <string.h>
+#include <pthread.h>
#include <signal.h>
+#include <string.h>
#include <time.h>
-#include "osi/include/alarm.h"
+#include <hardware/bluetooth.h>
+
#include "osi/include/allocator.h"
#include "osi/include/list.h"
#include "osi/include/log.h"
// a guarantee to its caller that the callback will not be in progress when it
// returns.
pthread_mutex_t callback_lock;
- period_ms_t created;
+ period_ms_t creation_time;
period_ms_t period;
period_ms_t deadline;
bool is_periodic;
alarm_t *ret = osi_calloc(sizeof(alarm_t));
if (!ret) {
- LOG_ERROR("%s unable to allocate memory for alarm.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for alarm.", __func__);
goto error;
}
// within the callback function of the alarm.
int error = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
if (error) {
- LOG_ERROR("%s unable to create a recursive mutex: %s", __func__, strerror(error));
+ LOG_ERROR(LOG_TAG, "%s unable to create a recursive mutex: %s", __func__, strerror(error));
goto error;
}
error = pthread_mutex_init(&ret->callback_lock, &attr);
if (error) {
- LOG_ERROR("%s unable to initialize mutex: %s", __func__, strerror(error));
+ LOG_ERROR(LOG_TAG, "%s unable to initialize mutex: %s", __func__, strerror(error));
goto error;
}
pthread_mutex_lock(&monitor);
- alarm->created = now();
+ alarm->creation_time = now();
alarm->is_periodic = is_periodic;
alarm->period = period;
alarm->callback = cb;
alarms = list_new(NULL);
if (!alarms) {
- LOG_ERROR("%s unable to allocate alarm list.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate alarm list.", __func__);
return false;
}
sigevent.sigev_notify = SIGEV_THREAD;
sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
if (timer_create(CLOCK_ID, &sigevent, &timer) == -1) {
- LOG_ERROR("%s unable to create timer: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to create timer: %s", __func__, strerror(errno));
return false;
}
alarm_expired = semaphore_new(0);
if (!alarm_expired) {
- LOG_ERROR("%s unable to create alarm expired semaphore", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create alarm expired semaphore", __func__);
return false;
}
callback_thread_active = true;
callback_thread = thread_new("alarm_callbacks");
if (!callback_thread) {
- LOG_ERROR("%s unable to create alarm callback thread.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__);
return false;
}
struct timespec ts;
if (clock_gettime(CLOCK_ID, &ts) == -1) {
- LOG_ERROR("%s unable to get current time: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__, strerror(errno));
return 0;
}
// Calculate the next deadline for this alarm
period_ms_t just_now = now();
- period_ms_t ms_into_period = alarm->is_periodic ? ((just_now - alarm->created) % alarm->period) : 0;
+ period_ms_t ms_into_period = alarm->is_periodic ? ((just_now - alarm->creation_time) % alarm->period) : 0;
alarm->deadline = just_now + (alarm->period - ms_into_period);
// Add it into the timer list sorted by deadline (earliest deadline first).
if (!timer_set) {
int status = bt_os_callouts->acquire_wake_lock(WAKE_LOCK_ID);
if (status != BT_STATUS_SUCCESS) {
- LOG_ERROR("%s unable to acquire wake lock: %d", __func__, status);
+ LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock: %d", __func__, status);
goto done;
}
}
wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
} else {
if (!bt_os_callouts->set_wake_alarm(next_expiration, true, timer_callback, NULL))
- LOG_ERROR("%s unable to set wake alarm for %" PRId64 "ms.", __func__, next_expiration);
+ LOG_ERROR(LOG_TAG, "%s unable to set wake alarm for %" PRId64 "ms.", __func__, next_expiration);
}
done:
}
if (timer_settime(timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
- LOG_ERROR("%s unable to set timer: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno));
// If next expiration was in the past (e.g. short timer that got context switched)
// then the timer might have diarmed itself. Detect this case and work around it
struct itimerspec time_to_expire;
timer_gettime(timer, &time_to_expire);
if (time_to_expire.it_value.tv_sec == 0 && time_to_expire.it_value.tv_nsec == 0) {
- LOG_ERROR("%s alarm expiration too close for posix timers, switching to guns", __func__);
+ LOG_ERROR(LOG_TAG, "%s alarm expiration too close for posix timers, switching to guns", __func__);
semaphore_post(alarm_expired);
}
}
pthread_mutex_unlock(&alarm->callback_lock);
}
- LOG_DEBUG("%s Callback thread exited", __func__);
+ LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__);
}
#define LOG_TAG "bt_osi_allocation_tracker"
+#include "osi/include/allocation_tracker.h"
+
#include <assert.h>
#include <pthread.h>
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include "osi/include/allocation_tracker.h"
#include "osi/include/allocator.h"
#include "osi/include/hash_functions.h"
#include "osi/include/hash_map.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
typedef struct {
uint8_t allocator_id;
return return_ptr;
}
-void *allocation_tracker_notify_free(uint8_t allocator_id, void *ptr) {
+void *allocation_tracker_notify_free(UNUSED_ATTR uint8_t allocator_id, void *ptr) {
if (!allocations || !ptr)
return ptr;
assert(allocation->allocator_id == allocator_id); // Must be from the same allocator
allocation->freed = true;
- const char *beginning_canary = ((char *)ptr) - canary_size;
- const char *end_canary = ((char *)ptr) + allocation->size;
+ UNUSED_ATTR const char *beginning_canary = ((char *)ptr) - canary_size;
+ UNUSED_ATTR const char *end_canary = ((char *)ptr) + allocation->size;
for (size_t i = 0; i < canary_size; i++) {
assert(beginning_canary[i] == canary[i]);
allocation_t *allocation = (allocation_t *)entry->data;
if (!allocation->freed) {
*((size_t *)context) += allocation->size; // Report back the unfreed byte count
- LOG_ERROR("%s found unfreed allocation. address: 0x%zx size: %zd bytes", __func__, (uintptr_t)allocation->ptr, allocation->size);
+ LOG_ERROR(LOG_TAG, "%s found unfreed allocation. address: 0x%zx size: %zd bytes", __func__, (uintptr_t)allocation->ptr, allocation->size);
}
return true;
* limitations under the License.
*
******************************************************************************/
-
#include <stdlib.h>
#include <string.h>
size_t real_size = allocation_tracker_resize_for_canary(size);
char *new_string = allocation_tracker_notify_alloc(
- alloc_allocator_id,
- malloc(real_size),
- size);
+ alloc_allocator_id,
+ malloc(real_size),
+ size);
+ if (!new_string)
+ return NULL;
+
+ memcpy(new_string, str, size);
+ return new_string;
+}
+
+char *osi_strndup(const char *str, size_t len) {
+ size_t size = strlen(str);
+ if (len < size)
+ size = len;
+
+ size_t real_size = allocation_tracker_resize_for_canary(size + 1);
+
+ char *new_string = allocation_tracker_notify_alloc(
+ alloc_allocator_id,
+ malloc(real_size),
+ size + 1);
if (!new_string)
return NULL;
memcpy(new_string, str, size);
+ new_string[size] = '\0';
return new_string;
}
#define LOG_TAG "bt_osi_array"
+#include "osi/include/array.h"
+
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "osi/include/allocator.h"
-#include "osi/include/array.h"
#include "osi/include/log.h"
struct array_t {
array_t *array = osi_calloc(sizeof(array_t) + element_size * INTERNAL_ELEMENTS);
if (!array) {
- LOG_ERROR("%s unable to allocate memory for array with elements of size %zu.", __func__, element_size);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for array with elements of size %zu.", __func__, element_size);
return NULL;
}
assert(data != NULL);
if (array->length == array->capacity && !grow(array)) {
- LOG_ERROR("%s unable to grow array past current capacity of %zu elements of size %zu.", __func__, array->capacity, array->element_size);
+ LOG_ERROR(LOG_TAG, "%s unable to grow array past current capacity of %zu elements of size %zu.", __func__, array->capacity, array->element_size);
return false;
}
#define LOG_TAG "bt_osi_buffer"
+#include "osi/include/buffer.h"
+
#include <assert.h>
#include <stdint.h>
#include "osi/include/allocator.h"
-#include "osi/include/buffer.h"
#include "osi/include/log.h"
struct buffer_t {
buffer_t *buffer = osi_calloc(sizeof(buffer_t) + size);
if (!buffer) {
- LOG_ERROR("%s unable to allocate buffer of %zu bytes.", __func__, size);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate buffer of %zu bytes.", __func__, size);
return NULL;
}
buffer_t *ret = osi_calloc(sizeof(buffer_t));
if (!ret) {
- LOG_ERROR("%s unable to allocate new buffer for slice of length %zu.", __func__, slice_size);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate new buffer for slice of length %zu.", __func__, slice_size);
return NULL;
}
#define LOG_TAG "bt_osi_config"
+#include "osi/include/config.h"
+
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <sys/stat.h>
#include "osi/include/allocator.h"
-#include "osi/include/config.h"
#include "osi/include/list.h"
#include "osi/include/log.h"
config_t *config_new_empty(void) {
config_t *config = osi_calloc(sizeof(config_t));
if (!config) {
- LOG_ERROR("%s unable to allocate memory for config_t.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for config_t.", __func__);
goto error;
}
config->sections = list_new(section_free);
if (!config->sections) {
- LOG_ERROR("%s unable to allocate list for sections.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate list for sections.", __func__);
goto error;
}
FILE *fp = fopen(filename, "rt");
if (!fp) {
- LOG_ERROR("%s unable to open file '%s': %s", __func__, filename, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to open file '%s': %s", __func__, filename, strerror(errno));
config_free(config);
return NULL;
}
char *temp_filename = osi_calloc(strlen(filename) + 5);
if (!temp_filename) {
- LOG_ERROR("%s unable to allocate memory for filename.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for filename.", __func__);
return false;
}
FILE *fp = fopen(temp_filename, "wt");
if (!fp) {
- LOG_ERROR("%s unable to write file '%s': %s", __func__, temp_filename, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to write file '%s': %s", __func__, temp_filename, strerror(errno));
goto error;
}
// Change the file's permissions to Read/Write by User and Group
if (chmod(temp_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1) {
- LOG_ERROR("%s unable to change file permissions '%s': %s", __func__, filename, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to change file permissions '%s': %s", __func__, filename, strerror(errno));
goto error;
}
if (rename(temp_filename, filename) == -1) {
- LOG_ERROR("%s unable to commit file '%s': %s", __func__, filename, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to commit file '%s': %s", __func__, filename, strerror(errno));
goto error;
}
if (*line_ptr == '[') {
size_t len = strlen(line_ptr);
if (line_ptr[len - 1] != ']') {
- LOG_DEBUG("%s unterminated section name on line %d.", __func__, line_num);
+ LOG_DEBUG(LOG_TAG, "%s unterminated section name on line %d.", __func__, line_num);
continue;
}
strncpy(section, line_ptr + 1, len - 2);
} else {
char *split = strchr(line_ptr, '=');
if (!split) {
- LOG_DEBUG("%s no key/value separator found on line %d.", __func__, line_num);
+ LOG_DEBUG(LOG_TAG, "%s no key/value separator found on line %d.", __func__, line_num);
continue;
}
#define LOG_TAG "bt_osi_data_dispatcher"
+#include "osi/include/data_dispatcher.h"
+
#include <assert.h>
#include "osi/include/allocator.h"
-#include "osi/include/data_dispatcher.h"
#include "osi/include/hash_functions.h"
#include "osi/include/hash_map.h"
#include "osi/include/osi.h"
data_dispatcher_t *ret = osi_calloc(sizeof(data_dispatcher_t));
if (!ret) {
- LOG_ERROR("%s unable to allocate memory for new data dispatcher.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for new data dispatcher.", __func__);
goto error;
}
ret->dispatch_table = hash_map_new(DEFAULT_TABLE_BUCKETS, hash_function_naive, NULL, NULL, NULL);
if (!ret->dispatch_table) {
- LOG_ERROR("%s unable to create dispatch table.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create dispatch table.", __func__);
goto error;
}
ret->name = osi_strdup(name);
if (!ret->name) {
- LOG_ERROR("%s unable to duplicate provided name.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to duplicate provided name.", __func__);
goto error;
}
if (queue)
fixed_queue_enqueue(queue, data);
else
- LOG_WARN("%s has no handler for type (%zd) in data dispatcher named: %s", __func__, type, dispatcher->name);
+ LOG_WARN(LOG_TAG, "%s has no handler for type (%zd) in data dispatcher named: %s", __func__, type, dispatcher->name);
return queue != NULL;
}
#define LOG_TAG "bt_osi_eager_reader"
+#include "osi/include/eager_reader.h"
+
#include <assert.h>
#include <errno.h>
-#include <stddef.h>
#include <string.h>
#include <sys/eventfd.h>
+#include <unistd.h>
-#include "osi/include/allocator.h"
-#include "osi/include/eager_reader.h"
#include "osi/include/fixed_queue.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/reactor.h"
#include "osi/include/thread.h"
eager_reader_t *ret = osi_calloc(sizeof(eager_reader_t));
if (!ret) {
- LOG_ERROR("%s unable to allocate memory for new eager_reader.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for new eager_reader.", __func__);
goto error;
}
ret->bytes_available_fd = eventfd(0, 0);
if (ret->bytes_available_fd == INVALID_FD) {
- LOG_ERROR("%s unable to create output reading semaphore.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create output reading semaphore.", __func__);
goto error;
}
ret->buffers = fixed_queue_new(max_buffer_count);
if (!ret->buffers) {
- LOG_ERROR("%s unable to create buffers queue.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create buffers queue.", __func__);
goto error;
}
ret->inbound_read_thread = thread_new(thread_name);
if (!ret->inbound_read_thread) {
- LOG_ERROR("%s unable to make reading thread.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to make reading thread.", __func__);
goto error;
}
// Find out how many bytes we have available in our various buffers.
eventfd_t bytes_available;
if (eventfd_read(reader->bytes_available_fd, &bytes_available) == -1) {
- LOG_ERROR("%s unable to read semaphore for output data.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to read semaphore for output data.", __func__);
return 0;
}
bytes_available -= bytes_consumed;
if (eventfd_write(reader->bytes_available_fd, bytes_available) == -1) {
- LOG_ERROR("%s unable to write back bytes available for output data.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to write back bytes available for output data.", __func__);
}
return bytes_consumed;
data_buffer_t *buffer = (data_buffer_t *)reader->allocator->alloc(reader->buffer_size + sizeof(data_buffer_t));
if (!buffer) {
- LOG_ERROR("%s couldn't aquire memory for inbound data buffer.", __func__);
+ LOG_ERROR(LOG_TAG, "%s couldn't aquire memory for inbound data buffer.", __func__);
return;
}
eventfd_write(reader->bytes_available_fd, bytes_read);
} else {
if (bytes_read == 0)
- LOG_WARN("%s fd said bytes existed, but none were found.", __func__);
+ LOG_WARN(LOG_TAG, "%s fd said bytes existed, but none were found.", __func__);
else
- LOG_WARN("%s unable to read from file descriptor: %s", __func__, strerror(errno));
+ LOG_WARN(LOG_TAG, "%s unable to read from file descriptor: %s", __func__, strerror(errno));
reader->allocator->free(buffer);
}
#include <assert.h>
#include <pthread.h>
-#include <stdlib.h>
#include "osi/include/allocator.h"
#include "osi/include/fixed_queue.h"
#define LOG_TAG "bt_osi_future"
+#include "osi/include/future.h"
+
#include <assert.h>
#include "osi/include/allocator.h"
-#include "osi/include/future.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/semaphore.h"
struct future_t {
future_t *future_new(void) {
future_t *ret = osi_calloc(sizeof(future_t));
if (!ret) {
- LOG_ERROR("%s unable to allocate memory for return value.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for return value.", __func__);
goto error;
}
ret->semaphore = semaphore_new(0);
if (!ret->semaphore) {
- LOG_ERROR("%s unable to allocate memory for the semaphore.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for the semaphore.", __func__);
goto error;
}
future_t *future_new_immediate(void *value) {
future_t *ret = osi_calloc(sizeof(future_t));
if (!ret) {
- LOG_ERROR("%s unable to allocate memory for return value.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for return value.", __func__);
goto error;
}
#include <hash_map.h>
#include "osi/include/allocator.h"
+#include "osi/include/osi.h"
struct hash_map_t;
if (hash_map_entry) {
// Calls hash_map callback to delete the hash_map_entry.
- bool rc = list_remove(hash_bucket_list, hash_map_entry);
+ UNUSED_ATTR bool rc = list_remove(hash_bucket_list, hash_map_entry);
assert(rc == true);
} else {
hash_map->hash_size++;
--- /dev/null
+/******************************************************************************
+ *
+ * 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 "hash_map_utils"
+
+#include "osi/include/hash_map_utils.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/hash_functions.h"
+#include "osi/include/hash_map.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+static bool string_equals(const void *key_a, const void *key_b);
+static bool dump_entry(hash_map_entry_t *entry, UNUSED_ATTR void *context);
+
+static const size_t BUCKETS_NUM = 5;
+
+hash_map_t *hash_map_utils_new_from_string_params(const char *params) {
+ assert(params != NULL);
+
+ hash_map_t *map = hash_map_new(BUCKETS_NUM, hash_function_string, osi_free,
+ osi_free, string_equals);
+ if (!map)
+ return NULL;
+
+ char *str = osi_strdup(params);
+ if (!str)
+ return NULL;
+
+ LOG_VERBOSE(LOG_TAG, "%s: source string: '%s'", __func__, str);
+
+ // Parse |str| and add extracted key-and-value pair(s) in |map|.
+ int items = 0;
+ char *tmpstr;
+ char *kvpair = strtok_r(str, ";", &tmpstr);
+ while (kvpair && *kvpair) {
+ char *eq = strchr(kvpair, '=');
+
+ if (eq == kvpair)
+ goto next_pair;
+
+ char *key;
+ char *value;
+ if (eq) {
+ key = osi_strndup(kvpair, eq - kvpair);
+
+ // The increment of |eq| moves |eq| to the beginning of the value.
+ ++eq;
+ value = (*eq != '\0') ? osi_strdup(eq) : osi_strdup("");
+ } else {
+ key = osi_strdup(kvpair);
+ value = osi_strdup("");
+ }
+
+ hash_map_set(map, key, value);
+
+ items++;
+next_pair:
+ kvpair = strtok_r(NULL, ";", &tmpstr);
+ }
+
+ if (!items)
+ LOG_VERBOSE(LOG_TAG, "%s: no items found in string\n", __func__);
+
+ osi_free(str);
+ return map;
+}
+
+void hash_map_utils_dump_string_keys_string_values(hash_map_t *map) {
+ if (!map) {
+ LOG_VERBOSE( LOG_TAG, "%s: the given map is NULL\n", __func__);
+ return;
+ }
+ hash_map_foreach(map, dump_entry, NULL);
+}
+
+static bool string_equals(const void *key_a, const void *key_b) {
+ return !strcmp(key_a, key_b);
+}
+
+static bool dump_entry(hash_map_entry_t *entry, UNUSED_ATTR void *context) {
+ hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)entry;
+ LOG_INFO(LOG_TAG, "key: '%s' value: '%s'\n", (char *)hash_map_entry->key,
+ (char *)hash_map_entry->data);
+ return true;
+}
#define LOG_TAG "bt_osi_reactor"
+#include "osi/include/reactor.h"
+
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
+#include <unistd.h>
#include "osi/include/allocator.h"
#include "osi/include/list.h"
#include "osi/include/log.h"
-#include "osi/include/reactor.h"
#if !defined(EFD_SEMAPHORE)
# define EFD_SEMAPHORE (1 << 0)
ret->epoll_fd = epoll_create(MAX_EVENTS);
if (ret->epoll_fd == INVALID_FD) {
- LOG_ERROR("%s unable to create epoll instance: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to create epoll instance: %s", __func__, strerror(errno));
goto error;
}
ret->event_fd = eventfd(0, 0);
if (ret->event_fd == INVALID_FD) {
- LOG_ERROR("%s unable to create eventfd: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to create eventfd: %s", __func__, strerror(errno));
goto error;
}
pthread_mutex_init(&ret->list_lock, NULL);
ret->invalidation_list = list_new(NULL);
if (!ret->invalidation_list) {
- LOG_ERROR("%s unable to allocate object invalidation list.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate object invalidation list.", __func__);
goto error;
}
event.events = EPOLLIN;
event.data.ptr = NULL;
if (epoll_ctl(ret->epoll_fd, EPOLL_CTL_ADD, ret->event_fd, &event) == -1) {
- LOG_ERROR("%s unable to register eventfd with epoll set: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to register eventfd with epoll set: %s", __func__, strerror(errno));
goto error;
}
reactor_object_t *object = (reactor_object_t *)osi_calloc(sizeof(reactor_object_t));
if (!object) {
- LOG_ERROR("%s unable to allocate reactor object: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to allocate reactor object: %s", __func__, strerror(errno));
return NULL;
}
event.data.ptr = object;
if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1) {
- LOG_ERROR("%s unable to register fd %d to epoll set: %s", __func__, fd, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to register fd %d to epoll set: %s", __func__, fd, strerror(errno));
pthread_mutex_destroy(&object->lock);
osi_free(object);
return NULL;
event.data.ptr = object;
if (epoll_ctl(object->reactor->epoll_fd, EPOLL_CTL_MOD, object->fd, &event) == -1) {
- LOG_ERROR("%s unable to modify interest set for fd %d: %s", __func__, object->fd, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to modify interest set for fd %d: %s", __func__, object->fd, strerror(errno));
return false;
}
reactor_t *reactor = obj->reactor;
if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_DEL, obj->fd, NULL) == -1)
- LOG_ERROR("%s unable to unregister fd %d from epoll set: %s", __func__, obj->fd, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to unregister fd %d from epoll set: %s", __func__, obj->fd, strerror(errno));
if (reactor->is_running && pthread_equal(pthread_self(), reactor->run_thread)) {
reactor->object_removed = true;
} while (ret == -1 && errno == EINTR);
if (ret == -1) {
- LOG_ERROR("%s error in epoll_wait: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s error in epoll_wait: %s", __func__, strerror(errno));
reactor->is_running = false;
return REACTOR_STATUS_ERROR;
}
#define LOG_TAG "bt_osi_semaphore"
+#include "osi/include/semaphore.h"
+
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <string.h>
#include <sys/eventfd.h>
+#include <unistd.h>
#include "osi/include/allocator.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
-#include "osi/include/semaphore.h"
+#include "osi/include/osi.h"
#if !defined(EFD_SEMAPHORE)
# define EFD_SEMAPHORE (1 << 0)
if (ret) {
ret->fd = eventfd(value, EFD_SEMAPHORE);
if (ret->fd == INVALID_FD) {
- LOG_ERROR("%s unable to allocate semaphore: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to allocate semaphore: %s", __func__, strerror(errno));
osi_free(ret);
ret = NULL;
}
uint64_t value;
if (eventfd_read(semaphore->fd, &value) == -1)
- LOG_ERROR("%s unable to wait on semaphore: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to wait on semaphore: %s", __func__, strerror(errno));
}
bool semaphore_try_wait(semaphore_t *semaphore) {
int flags = fcntl(semaphore->fd, F_GETFL);
if (flags == -1) {
- LOG_ERROR("%s unable to get flags for semaphore fd: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to get flags for semaphore fd: %s", __func__, strerror(errno));
return false;
}
if (fcntl(semaphore->fd, F_SETFL, flags | O_NONBLOCK) == -1) {
- LOG_ERROR("%s unable to set O_NONBLOCK for semaphore fd: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to set O_NONBLOCK for semaphore fd: %s", __func__, strerror(errno));
return false;
}
return false;
if (fcntl(semaphore->fd, F_SETFL, flags) == -1)
- LOG_ERROR("%s unable to resetore flags for semaphore fd: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to resetore flags for semaphore fd: %s", __func__, strerror(errno));
return true;
}
assert(semaphore->fd != INVALID_FD);
if (eventfd_write(semaphore->fd, 1ULL) == -1)
- LOG_ERROR("%s unable to post to semaphore: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to post to semaphore: %s", __func__, strerror(errno));
}
int semaphore_get_fd(const semaphore_t *semaphore) {
#define LOG_TAG "bt_osi_socket"
+#include "osi/include/socket.h"
+
#include <asm/ioctls.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <sys/types.h>
#include <unistd.h>
#include "osi/include/allocator.h"
-#include "osi/include/osi.h"
#include "osi/include/log.h"
+#include "osi/include/osi.h"
#include "osi/include/reactor.h"
-#include "osi/include/socket.h"
// The IPv4 loopback address: 127.0.0.1
static const in_addr_t LOCALHOST_ = 0x7f000001;
socket_t *socket_new(void) {
socket_t *ret = (socket_t *)osi_calloc(sizeof(socket_t));
if (!ret) {
- LOG_ERROR("%s unable to allocate memory for socket.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for socket.", __func__);
goto error;
}
ret->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ret->fd == INVALID_FD) {
- LOG_ERROR("%s unable to create socket: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to create socket: %s", __func__, strerror(errno));
goto error;
}
int enable = 1;
if (setsockopt(ret->fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
- LOG_ERROR("%s unable to set SO_REUSEADDR: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to set SO_REUSEADDR: %s", __func__, strerror(errno));
goto error;
}
socket_t *ret = (socket_t *)osi_calloc(sizeof(socket_t));
if (!ret) {
- LOG_ERROR("%s unable to allocate memory for socket.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for socket.", __func__);
return NULL;
}
addr.sin_addr.s_addr = htonl(LOCALHOST_);
addr.sin_port = htons(port);
if (bind(socket->fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
- LOG_ERROR("%s unable to bind socket to port %u: %s", __func__, port, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to bind socket to port %u: %s", __func__, port, strerror(errno));
return false;
}
if (listen(socket->fd, 10) == -1) {
- LOG_ERROR("%s unable to listen on port %u: %s", __func__, port, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to listen on port %u: %s", __func__, port, strerror(errno));
return false;
}
int fd = accept(socket->fd, NULL, NULL);
if (fd == INVALID_FD) {
- LOG_ERROR("%s unable to accept socket: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to accept socket: %s", __func__, strerror(errno));
return NULL;
}
socket_t *ret = (socket_t *)osi_calloc(sizeof(socket_t));
if (!ret) {
close(fd);
- LOG_ERROR("%s unable to allocate memory for socket.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for socket.", __func__);
return NULL;
}
--- /dev/null
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.
+ */
+
+The sources in this folder re-implement some of the sources in libcutils/sockets
+to provide a short-term solution eliminating libcutils dependency from
+system/bt. Once a long-term platform-independent abstraction is presented, these
+sources and the corresponding headers should be removed.
+
+Note that only a part of the source files are pulled from libcutils/sockets, and
+"osi_" prefix is added to all functions. The developers who want to pull sockets
+sources other than the existing ones must put the sources in this folder and
+refactor the functions as well.
+
+The current sources include:
+
+[Headers]
+ - osi/include/socket_utils/sockets.h
+ - osi/include/socket_utils/socket_local.h
+[Source files]
+ - osi/src/socket_utils/socket_local_client.c
+ - osi/src/socket_utils/socket_local_server.c
+
+Please update the above list if adding more sources.
--- /dev/null
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "osi/include/osi.h"
+#include "osi/include/socket_utils/sockets.h"
+#include "osi/include/socket_utils/socket_local.h"
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+int osi_socket_make_sockaddr_un(const char *name, int namespaceId,
+ struct sockaddr_un *p_addr, socklen_t *alen) {
+ memset(p_addr, 0, sizeof(*p_addr));
+ size_t namelen;
+
+ switch (namespaceId) {
+ case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#if defined(__linux__)
+ namelen = strlen(name);
+
+ // Test with length +1 for the *initial* '\0'.
+ if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+ goto error;
+ }
+
+ /*
+ * Note: The path in this case is *not* supposed to be
+ * '\0'-terminated. ("man 7 unix" for the gory details.)
+ */
+
+ p_addr->sun_path[0] = 0;
+ memcpy(p_addr->sun_path + 1, name, namelen);
+#else
+ /* this OS doesn't have the Linux abstract namespace */
+
+ namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen >
+ sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+#endif
+ break;
+
+ case ANDROID_SOCKET_NAMESPACE_RESERVED:
+ namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen >
+ sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+ break;
+
+ case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+ namelen = strlen(name);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen >
+ sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, name);
+ break;
+ default:
+ // invalid namespace id
+ return -1;
+ }
+
+ p_addr->sun_family = AF_LOCAL;
+ *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+ return 0;
+error:
+ return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ *
+ * Used by AndroidSocketImpl
+ */
+int osi_socket_local_client_connect(int fd, const char *name, int namespaceId,
+ int type UNUSED_ATTR) {
+ struct sockaddr_un addr;
+ socklen_t alen;
+ int err;
+
+ err = osi_socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+ if (err < 0) {
+ goto error;
+ }
+
+ if (connect(fd, (struct sockaddr *)&addr, alen) < 0) {
+ goto error;
+ }
+
+ return fd;
+
+error:
+ return -1;
+}
+
+/**
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+int osi_socket_local_client(const char *name, int namespaceId, int type) {
+ int s;
+
+ s = socket(AF_LOCAL, type, 0);
+ if (s < 0) return -1;
+
+ if (0 > osi_socket_local_client_connect(s, name, namespaceId, type)) {
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2006, The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include <errno.h>
+#include <netinet/in.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "osi/include/socket_utils/sockets.h"
+#include "osi/include/socket_utils/socket_local.h"
+
+#define LISTEN_BACKLOG 4
+
+/* Only the bottom bits are really the socket type; there are flags too. */
+#define SOCK_TYPE_MASK 0xf
+
+/**
+ * Binds a pre-created socket(AF_LOCAL) 's' to 'name'
+ * returns 's' on success, -1 on fail
+ *
+ * Does not call listen()
+ */
+int osi_socket_local_server_bind(int s, const char *name, int namespaceId) {
+ struct sockaddr_un addr;
+ socklen_t alen;
+ int n;
+ int err;
+
+ err = osi_socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+ if (err < 0) {
+ return -1;
+ }
+
+/* basically: if this is a filesystem path, unlink first */
+#if !defined(__linux__)
+ if (1) {
+#else
+ if (namespaceId == ANDROID_SOCKET_NAMESPACE_RESERVED ||
+ namespaceId == ANDROID_SOCKET_NAMESPACE_FILESYSTEM) {
+#endif
+ /*ignore ENOENT*/
+ unlink(addr.sun_path);
+ }
+
+ n = 1;
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+ if (bind(s, (struct sockaddr *)&addr, alen) < 0) {
+ return -1;
+ }
+
+ return s;
+}
+
+/** Open a server-side UNIX domain datagram socket in the Linux non-filesystem
+ * namespace
+ *
+ * Returns fd on success, -1 on fail
+ */
+int osi_socket_local_server(const char *name, int namespace, int type) {
+ int err;
+ int s;
+
+ s = socket(AF_LOCAL, type, 0);
+ if (s < 0) return -1;
+
+ err = osi_socket_local_server_bind(s, name, namespace);
+
+ if (err < 0) {
+ close(s);
+ return -1;
+ }
+
+ if ((type & SOCK_TYPE_MASK) == SOCK_STREAM) {
+ int ret;
+
+ ret = listen(s, LISTEN_BACKLOG);
+
+ if (ret < 0) {
+ close(s);
+ return -1;
+ }
+ }
+
+ return s;
+}
#define LOG_TAG "bt_osi_thread"
+#include "osi/include/thread.h"
+
#include <assert.h>
#include <errno.h>
#include <malloc.h>
#include "osi/include/log.h"
#include "osi/include/reactor.h"
#include "osi/include/semaphore.h"
-#include "osi/include/thread.h"
struct thread_t {
bool is_joined;
// or when the item is removed from the queue for dispatch.
work_item_t *item = (work_item_t *)osi_malloc(sizeof(work_item_t));
if (!item) {
- LOG_ERROR("%s unable to allocate memory: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory: %s", __func__, strerror(errno));
return false;
}
item->func = func;
assert(thread != NULL);
if (prctl(PR_SET_NAME, (unsigned long)thread->name) == -1) {
- LOG_ERROR("%s unable to set thread name: %s", __func__, strerror(errno));
+ LOG_ERROR(LOG_TAG, "%s unable to set thread name: %s", __func__, strerror(errno));
start->error = errno;
semaphore_post(start->start_sem);
return NULL;
}
if (count > fixed_queue_capacity(thread->work_queue))
- LOG_DEBUG("%s growing event queue on shutdown.", __func__);
+ LOG_DEBUG(LOG_TAG, "%s growing event queue on shutdown.", __func__);
return NULL;
}
--- /dev/null
+/******************************************************************************
+ *
+ * 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
+ *
+ ******************************************************************************/
+#include <cstring>
+
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+extern "C" {
+#include "osi/include/allocator.h"
+}
+
+class AllocatorTest : public AllocationTestHarness {};
+
+TEST_F(AllocatorTest, test_osi_strndup) {
+ char str[] = "IloveBluetooth";
+ size_t len = strlen(str);
+ char *copy_str = NULL;
+
+ // len == 0
+ copy_str = osi_strndup(str, 0);
+ EXPECT_EQ(0, strcmp(copy_str, ""));
+ osi_free(copy_str);
+
+ // len == strlen(str)
+ copy_str = osi_strndup(str, len);
+ EXPECT_EQ(0, strcmp(str, copy_str));
+ osi_free(copy_str);
+
+ // len < strlen(str)
+ copy_str = osi_strndup(str, len - 5);
+ EXPECT_EQ(0, strcmp("IloveBlue", copy_str));
+ osi_free(copy_str);
+
+ // len > strlen(str)
+ copy_str = osi_strndup(str, len + 5);
+ EXPECT_EQ(0, strcmp(str, copy_str));
+ osi_free(copy_str);
+}
+++ /dev/null
-#include <gtest/gtest.h>
-
-extern "C" {
-#include "atomic.h"
-}
-
-const static size_t ATOMIC_DATA_MAX = 2;
-const static int ATOMIC_MAX_THREADS = 20;
-
-struct atomic_test_s32_s {
- pthread_t pthread_id;
- int thread_num;
- int max_val;
- atomic_s32_t *data;
-};
-
-void *atomic_thread(void *context) {
- struct atomic_test_s32_s *at = (struct atomic_test_s32_s *)context;
- for (int i = 0; i < at->max_val; i++) {
- usleep(1);
- atomic_inc_prefix_s32(&at->data[i]);
- }
- return NULL;
-}
-
-void *atomic_thread_inc_dec(void *context) {
- struct atomic_test_s32_s *at = (struct atomic_test_s32_s *)context;
- for (int i = 0; i < at->max_val; i++) {
- usleep(1);
- atomic_inc_prefix_s32(&at->data[i]);
- usleep(1);
- atomic_dec_prefix_s32(&at->data[i]);
- }
- return NULL;
-}
-
-TEST(AtomicTest, test_store_load_s32) {
- atomic_s32_t data;
-
- atomic_store_s32(&data, -1);
- EXPECT_EQ(-1, atomic_load_s32(&data));
-
- atomic_store_s32(&data, 0);
- EXPECT_EQ(0, atomic_load_s32(&data));
-
- atomic_store_s32(&data, 1);
- EXPECT_EQ(1, atomic_load_s32(&data));
-
- atomic_store_s32(&data, 2);
- EXPECT_EQ(2, atomic_load_s32(&data));
-}
-
-TEST(AtomicTest, test_store_load_u32) {
- atomic_u32_t data;
-
- atomic_store_u32(&data, -1);
- EXPECT_EQ((uint32_t)-1, atomic_load_u32(&data));
-
- atomic_store_u32(&data, 0);
- EXPECT_EQ((uint32_t)0, atomic_load_u32(&data));
-
- atomic_store_u32(&data, 1);
- EXPECT_EQ((uint32_t)1, atomic_load_u32(&data));
-
- atomic_store_u32(&data, 2);
- EXPECT_EQ((uint32_t)2, atomic_load_u32(&data));
-}
-
-TEST(AtomicTest, test_inc_dec_s32) {
- atomic_s32_t data;
-
- atomic_store_s32(&data, 0);
- EXPECT_EQ(0, atomic_load_s32(&data));
-
- int32_t val = atomic_inc_prefix_s32(&data);
- EXPECT_EQ(1, atomic_load_s32(&data));
- EXPECT_EQ(1, val);
-
- val = atomic_inc_prefix_s32(&data);
- EXPECT_EQ(2, atomic_load_s32(&data));
- EXPECT_EQ(2, val);
-
- val = atomic_inc_prefix_s32(&data);
- EXPECT_EQ(3, atomic_load_s32(&data));
- EXPECT_EQ(3, val);
-
- val = atomic_dec_prefix_s32(&data);
- EXPECT_EQ(2, val);
-
- val = atomic_dec_prefix_s32(&data);
- EXPECT_EQ(1, val);
- val = atomic_dec_prefix_s32(&data);
- EXPECT_EQ(0, val);
- val = atomic_dec_prefix_s32(&data);
- EXPECT_EQ(-1, val);
-}
-
-TEST(AtomicTest, test_inc_dec_u32) {
- atomic_u32_t data;
-
- atomic_store_u32(&data, 0);
- EXPECT_EQ((unsigned)0, atomic_load_u32(&data));
-
- uint32_t val = atomic_inc_prefix_u32(&data);
- EXPECT_EQ((unsigned)1, atomic_load_u32(&data));
- EXPECT_EQ((unsigned)1, val);
-
- val = atomic_inc_prefix_u32(&data);
- EXPECT_EQ((unsigned)2, atomic_load_u32(&data));
- EXPECT_EQ((unsigned)2, val);
-
- val = atomic_inc_prefix_u32(&data);
- EXPECT_EQ((unsigned)3, atomic_load_u32(&data));
- EXPECT_EQ((unsigned)3, val);
-
- val = atomic_dec_prefix_u32(&data);
- EXPECT_EQ((unsigned)2, val);
-
- val = atomic_dec_prefix_u32(&data);
- EXPECT_EQ((unsigned)1, val);
- val = atomic_dec_prefix_u32(&data);
- EXPECT_EQ((unsigned)0, val);
- val = atomic_dec_prefix_u32(&data);
- EXPECT_EQ((unsigned)-1, val);
-}
-
-TEST(AtomicTest, test_atomic_inc_thread) {
- struct atomic_test_s32_s atomic_test[ATOMIC_MAX_THREADS];
- atomic_s32_t data[ATOMIC_DATA_MAX];
-
- memset(&atomic_test, 0, sizeof(atomic_test));
- memset(data, 0, sizeof(data));
-
- for (unsigned int i = 0; i < ATOMIC_DATA_MAX; i++) {
- EXPECT_EQ(0, data[i]._val);
- }
-
- for (int i = 0; i < ATOMIC_MAX_THREADS; i++) {
- atomic_test[i].thread_num = i;
- atomic_test[i].max_val = ATOMIC_DATA_MAX;
- atomic_test[i].data = data;
- pthread_create(&atomic_test[i].pthread_id, NULL, atomic_thread, &atomic_test[i]);
- }
-
- for (int i = 0; i < ATOMIC_MAX_THREADS; i++) {
- int rc = pthread_join(atomic_test[i].pthread_id, NULL);
- EXPECT_EQ(0, rc);
- }
-
- for (unsigned int i = 0; i < ATOMIC_DATA_MAX; i++) {
- EXPECT_EQ(1 * ATOMIC_MAX_THREADS, data[i]._val);
- }
-}
-
-TEST(AtomicTest, test_atomic_inc_thread_single) {
- struct atomic_test_s32_s atomic_test[ATOMIC_MAX_THREADS];
- atomic_s32_t data;
-
- memset(&atomic_test, 0, sizeof(atomic_test));
- memset(&data, 0, sizeof(data));
-
- EXPECT_EQ(0, data._val);
-
- for (int i = 0; i < ATOMIC_MAX_THREADS; i++) {
- atomic_test[i].thread_num = i;
- atomic_test[i].max_val = 1;
- atomic_test[i].data = &data;
- pthread_create(&atomic_test[i].pthread_id, NULL, atomic_thread_inc_dec, &atomic_test[i]);
- }
-
- for (int i = 0; i < ATOMIC_MAX_THREADS; i++) {
- int rc = pthread_join(atomic_test[i].pthread_id, NULL);
- EXPECT_EQ(0, rc);
- }
- EXPECT_EQ(0, data._val);
-}
-
-TEST(AtomicTest, test_store_load_s64) {
- atomic_s64_t data;
-
- atomic_store_s64(&data, -1);
- EXPECT_EQ(-1, atomic_load_s64(&data));
-
- atomic_store_s64(&data, 0);
- EXPECT_EQ(0, atomic_load_s64(&data));
-
- atomic_store_s64(&data, 1);
- EXPECT_EQ(1, atomic_load_s64(&data));
-
- atomic_store_s64(&data, 2);
- EXPECT_EQ(2, atomic_load_s64(&data));
-}
-
-TEST(AtomicTest, test_inc_dec_s64) {
- atomic_s64_t data;
-
- atomic_store_s64(&data, 0);
- EXPECT_EQ(0, atomic_load_s64(&data));
-
- int64_t val = atomic_inc_prefix_s64(&data);
- EXPECT_EQ(1, atomic_load_s64(&data));
- EXPECT_EQ(1, val);
-
- val = atomic_inc_prefix_s64(&data);
- EXPECT_EQ(2, atomic_load_s64(&data));
- EXPECT_EQ(2, val);
-
- val = atomic_inc_prefix_s64(&data);
- EXPECT_EQ(3, atomic_load_s64(&data));
- EXPECT_EQ(3, val);
-
- val = atomic_dec_prefix_s64(&data);
- EXPECT_EQ(2, val);
-
- val = atomic_dec_prefix_s64(&data);
- EXPECT_EQ(1, val);
- val = atomic_dec_prefix_s64(&data);
- EXPECT_EQ(0, val);
- val = atomic_dec_prefix_s64(&data);
- EXPECT_EQ(-1, val);
-
- // Mutating using postfix.
- val = atomic_inc_postfix_s64(&data);
- EXPECT_EQ(0, atomic_load_s64(&data));
- EXPECT_EQ(-1, val);
-
- val = atomic_inc_postfix_s64(&data);
- EXPECT_EQ(1, atomic_load_s64(&data));
- EXPECT_EQ(0, val);
-
- val = atomic_inc_postfix_s64(&data);
- EXPECT_EQ(2, atomic_load_s64(&data));
- EXPECT_EQ(1, val);
-
- val = atomic_dec_postfix_s64(&data);
- EXPECT_EQ(2, val);
-
- val = atomic_dec_postfix_s64(&data);
- EXPECT_EQ(1, val);
- val = atomic_dec_postfix_s64(&data);
- EXPECT_EQ(0, val);
- val = atomic_dec_postfix_s64(&data);
- EXPECT_EQ(-1, val);
- EXPECT_EQ(-2, atomic_load_s64(&data));
-}
-
-TEST(AtomicTest, test_add_sub_u64) {
- atomic_u64_t data;
-
- atomic_store_u64(&data, 0);
- EXPECT_EQ((unsigned)0, atomic_load_u64(&data));
-
- uint64_t val = atomic_add_u64(&data, 0xffff);
- EXPECT_EQ((unsigned)0xffff, atomic_load_u64(&data));
- EXPECT_EQ((unsigned)0xffff, val);
-
- val = atomic_add_u64(&data, 0xffff);
- EXPECT_EQ((unsigned)(2 * 0xffff), atomic_load_u64(&data));
- EXPECT_EQ((unsigned)(2 * 0xffff), val);
-
- val = atomic_add_u64(&data, 0xffff);
- EXPECT_EQ((unsigned)(3 * 0xffff), atomic_load_u64(&data));
- EXPECT_EQ((unsigned)(3 * 0xffff), val);
- EXPECT_NE((unsigned)(3 * 0xfff0), val);
-
- val = atomic_sub_u64(&data, 0xffff);
- EXPECT_EQ((unsigned)(2 * 0xffff), val);
-
- val = atomic_sub_u64(&data, 0);
- EXPECT_EQ((unsigned)(2 * 0xffff), val);
- val = atomic_sub_u64(&data, 0xffff);
- EXPECT_EQ((unsigned)(1 * 0xffff), val);
-
- val = atomic_sub_u64(&data, 0xffff);
- EXPECT_EQ((unsigned)0, val);
-}
-
-
--- /dev/null
+/******************************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************************/
+#include <cstring>
+
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+extern "C" {
+#include "osi/include/hash_map.h"
+#include "osi/include/hash_map_utils.h"
+#include "osi/include/allocator.h"
+}
+
+class HashMapUtilsTest : public AllocationTestHarness {
+ protected:
+ virtual void SetUp() {
+ AllocationTestHarness::SetUp();
+ map = NULL;
+ }
+ virtual void TearDown() {
+ hash_map_free(map);
+ AllocationTestHarness::TearDown();
+ }
+
+ hash_map_t *map;
+};
+
+TEST_F(HashMapUtilsTest, test_empty_string_params) {
+ char params[] = "";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_TRUE(hash_map_is_empty(map));
+}
+
+TEST_F(HashMapUtilsTest, test_semicolons) {
+ char params[] = ";;;";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_TRUE(hash_map_is_empty(map));
+}
+
+TEST_F(HashMapUtilsTest, test_equal_sign_in_value) {
+ char params[] = "keyOfSomething=value=OfSomething";
+ char key[] = "keyOfSomething";
+ char value[] = "value=OfSomething";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(1u, hash_map_size(map));
+ EXPECT_EQ(0, strcmp(value, (char *)hash_map_get(map, key)));
+}
+
+TEST_F(HashMapUtilsTest, test_two_pairs_with_same_key) {
+ char params[] = "key=valu0;key=value1";
+ char key[] = "key";
+ char value1[] = "value1";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(1u, hash_map_size(map));
+ EXPECT_EQ(0, strcmp(value1, (char *)hash_map_get(map, key)));
+}
+
+TEST_F(HashMapUtilsTest, test_one_key_value_pair_without_semicolon) {
+ char params[] = "keyOfSomething=valueOfSomething";
+ char key[] = "keyOfSomething";
+ char value[] = "valueOfSomething";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(1u, hash_map_size(map));
+ EXPECT_EQ(0, strcmp(value, (char *)hash_map_get(map, key)));
+}
+
+TEST_F(HashMapUtilsTest, test_one_key_value_pair_with_semicolon) {
+ char params[] = "keyOfSomething=valueOfSomething;";
+ char key[] = "keyOfSomething";
+ char value[] = "valueOfSomething";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(1u, hash_map_size(map));
+ EXPECT_EQ(0, strcmp(value, (char *)hash_map_get(map, key)));
+}
+
+TEST_F(HashMapUtilsTest, test_one_pair_with_empty_value) {
+ char params[] = "keyOfSomething=;";
+ char key[] = "keyOfSomething";
+ char value[] = "";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(1u, hash_map_size(map));
+ EXPECT_EQ(0, strcmp(value, (char *)hash_map_get(map, key)));
+}
+
+TEST_F(HashMapUtilsTest, test_one_pair_with_empty_key) {
+ char params[] = "=valueOfSomething;";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_TRUE(hash_map_is_empty(map));
+}
+
+TEST_F(HashMapUtilsTest, test_two_key_value_pairs) {
+ char params[] = "key0=value0;key1=value1;";
+ char key0[] = "key0";
+ char value0[] = "value0";
+ char key1[] = "key1";
+ char value1[] = "value1";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(2u, hash_map_size(map));
+ EXPECT_EQ(0, strcmp(value0, (char *)hash_map_get(map, key0)));
+ EXPECT_EQ(0, strcmp(value1, (char *)hash_map_get(map, key1)));
+}
+
+TEST_F(HashMapUtilsTest, test_dump_null_map) {
+ hash_map_t *map = NULL;
+ hash_map_utils_dump_string_keys_string_values(map);
+}
return NULL;
}
-const module_t profile_manager_module = {
+EXPORT_SYMBOL const module_t profile_manager_module = {
.name = PROFILE_MANAGER_MODULE,
.init = init,
.start_up = NULL,
--- /dev/null
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+# Common variables
+# ========================================================
+btserviceCommonSrc := \
+ adapter.cpp \
+ adapter_state.cpp \
+ daemon.cpp \
+ gatt_server.cpp \
+ hal/bluetooth_interface.cpp \
+ ipc/ipc_handler.cpp \
+ ipc/ipc_handler_unix.cpp \
+ ipc/ipc_manager.cpp \
+ ipc/unix_ipc_host.cpp \
+ logging_helpers.cpp \
+ settings.cpp \
+ util/atomic_string.cpp \
+ uuid.cpp
+
+btserviceBinderSrc := \
+ ipc/binder/bluetooth_binder_server.cpp \
+ ipc/binder/IBluetooth.cpp \
+ ipc/binder/IBluetoothCallback.cpp \
+ ipc/binder/ipc_handler_binder.cpp
+
+btserviceCommonIncludes := $(LOCAL_PATH)/../
+
+# Native system service for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ $(btserviceBinderSrc) \
+ $(btserviceCommonSrc) \
+ main.cpp
+LOCAL_C_INCLUDES += $(btserviceCommonIncludes)
+LOCAL_CFLAGS += -std=c++11
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bluetoothtbd
+LOCAL_REQUIRED_MODULES = bluetooth.default
+LOCAL_STATIC_LIBRARIES += libbtcore
+LOCAL_SHARED_LIBRARIES += \
+ libbinder \
+ libchrome \
+ libcutils \
+ libhardware \
+ liblog \
+ libutils
+include $(BUILD_EXECUTABLE)
+
+# Native system service unittests for host
+# ========================================================
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ $(btserviceCommonSrc) \
+ hal/fake_bluetooth_interface.cpp \
+ test/adapter_unittest.cpp \
+ test/fake_hal_util.cpp \
+ test/ipc_unix_unittest.cpp \
+ test/settings_unittest.cpp \
+ test/stub_ipc_handler_binder.cpp \
+ test/uuid_unittest.cpp
+LOCAL_C_INCLUDES += $(btserviceCommonIncludes)
+LOCAL_CFLAGS += -std=c++11
+LOCAL_LDLIBS += -lrt
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := bt_service_unittests
+LOCAL_SHARED_LIBRARIES += libchrome-host
+LOCAL_STATIC_LIBRARIES += libgmock_host liblog
+include $(BUILD_HOST_NATIVE_TEST)
+endif
+
+# Native system service CLI for target
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ $(btserviceBinderSrc) \
+ adapter_state.cpp \
+ client/main.cpp
+LOCAL_C_INCLUDES += $(btserviceCommonIncludes)
+LOCAL_CFLAGS += -std=c++11
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bluetooth-cli
+LOCAL_SHARED_LIBRARIES += \
+ libbinder \
+ libchrome \
+ libutils
+include $(BUILD_EXECUTABLE)
--- /dev/null
+#
+# 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.
+#
+
+source_set("service") {
+ sources = [
+ "a2dp_source.cpp",
+ "core_stack.cpp",
+ "daemon.cpp",
+ "gatt_server.cpp",
+ "ipc/ipc_handler.cpp",
+ "ipc/ipc_handler_unix.cpp",
+ "ipc/ipc_manager.cpp",
+ "ipc/unix_ipc_host.cpp",
+ "logging_helpers.cpp",
+ "settings.cpp",
+ "uuid.cpp"
+ ]
+
+ include_dirs = [
+ "//",
+ "//third_party/libchrome"
+ ]
+}
+
+executable("bluetoothtbd") {
+ sources = [
+ "main.cpp"
+ ]
+
+ deps = [
+ ":service",
+ "//btcore",
+ "//third_party/libchrome:base",
+ "//third_party/modp_b64"
+ ]
+
+ include_dirs = [
+ "//",
+ "//third_party/libchrome"
+ ]
+
+ libs = [ "-ldl", "-lpthread", "-lrt" ]
+}
+
+executable("service_unittests") {
+ testonly = true
+ sources = [
+ "test/fake_hal_util.cpp",
+ "test/ipc_unix_unittest.cpp",
+ "test/settings_unittest.cpp",
+ "test/uuid_unittest.cpp",
+ ]
+
+ include_dirs = [
+ "//",
+ "//third_party/gmock/include",
+ "//third_party/libchrome"
+ ]
+
+ deps = [
+ ":service",
+ "//third_party/gmock:gmock_main",
+ "//third_party/gtest:gtest_main",
+ "//third_party/libchrome:base",
+ "//third_party/modp_b64",
+ ]
+}
--- /dev/null
+//
+// 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.
+//
+
+#include "service/adapter.h"
+
+#include <base/logging.h>
+
+#include "service/logging_helpers.h"
+
+namespace bluetooth {
+
+// static
+const char Adapter::kDefaultAddress[] = "00:00:00:00:00:00";
+// static
+const char Adapter::kDefaultName[] = "not-initialized";
+
+void Adapter::Observer::OnAdapterStateChanged(Adapter* adapter,
+ AdapterState prev_state,
+ AdapterState new_state) {
+ // Default implementation does nothing
+}
+
+Adapter::Adapter()
+ : state_(ADAPTER_STATE_OFF),
+ address_(kDefaultAddress),
+ name_(kDefaultName) {
+ hal::BluetoothInterface::Get()->AddObserver(this);
+ hal::BluetoothInterface::Get()->GetHALInterface()->get_adapter_properties();
+}
+
+Adapter::~Adapter() {
+ hal::BluetoothInterface::Get()->RemoveObserver(this);
+}
+
+void Adapter::AddObserver(Observer* observer) {
+ std::lock_guard<std::mutex> lock(observers_lock_);
+ observers_.AddObserver(observer);
+}
+
+void Adapter::RemoveObserver(Observer* observer) {
+ std::lock_guard<std::mutex> lock(observers_lock_);
+ observers_.RemoveObserver(observer);
+}
+
+AdapterState Adapter::GetState() const {
+ return state_.load();
+}
+
+bool Adapter::IsEnabled() const {
+ return state_.load() == ADAPTER_STATE_ON;
+}
+
+bool Adapter::Enable() {
+ AdapterState current_state = GetState();
+ if (current_state != ADAPTER_STATE_OFF) {
+ LOG(INFO) << "Adapter not disabled - state: "
+ << AdapterStateToString(current_state);
+ return false;
+ }
+
+ // Set the state before calling enable() as there might be a race between here
+ // and the AdapterStateChangedCallback.
+ state_ = ADAPTER_STATE_TURNING_ON;
+ NotifyAdapterStateChanged(current_state, state_);
+
+ int status = hal::BluetoothInterface::Get()->GetHALInterface()->enable();
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to enable Bluetooth - status: "
+ << BtStatusText((const bt_status_t)status);
+ state_ = ADAPTER_STATE_OFF;
+ NotifyAdapterStateChanged(ADAPTER_STATE_TURNING_ON, state_);
+ return false;
+ }
+
+ return true;
+}
+
+bool Adapter::Disable() {
+ if (!IsEnabled()) {
+ LOG(INFO) << "Adapter is not enabled";
+ return false;
+ }
+
+ AdapterState current_state = GetState();
+
+ // Set the state before calling enable() as there might be a race between here
+ // and the AdapterStateChangedCallback.
+ state_ = ADAPTER_STATE_TURNING_OFF;
+ NotifyAdapterStateChanged(current_state, state_);
+
+ int status = hal::BluetoothInterface::Get()->GetHALInterface()->disable();
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to disable Bluetooth - status: "
+ << BtStatusText((const bt_status_t)status);
+ state_ = current_state;
+ NotifyAdapterStateChanged(ADAPTER_STATE_TURNING_OFF, state_);
+ return false;
+ }
+
+ return true;
+}
+
+std::string Adapter::GetName() const {
+ return name_.Get();
+}
+
+bool Adapter::SetName(const std::string& name) {
+ bt_bdname_t hal_name;
+ size_t max_name_len = sizeof(hal_name.name);
+
+ // Include the \0 byte in size measurement.
+ if (name.length() >= max_name_len) {
+ LOG(ERROR) << "Given name \"" << name << "\" is larger than maximum allowed"
+ << " size: " << max_name_len;
+ return false;
+ }
+
+ strncpy(reinterpret_cast<char*>(hal_name.name), name.c_str(),
+ name.length() + 1);
+
+ VLOG(1) << "Setting adapter name: " << name;
+
+ if (!SetAdapterProperty(BT_PROPERTY_BDNAME, &hal_name, sizeof(hal_name))) {
+ LOG(ERROR) << "Failed to set adapter name: " << name;
+ return false;
+ }
+
+ return true;
+}
+
+std::string Adapter::GetAddress() const {
+ return address_.Get();
+}
+
+void Adapter::AdapterStateChangedCallback(bt_state_t state) {
+ LOG(INFO) << "Adapter state changed: " << BtStateText(state);
+
+ AdapterState prev_state = GetState();
+
+ switch (state) {
+ case BT_STATE_OFF:
+ state_ = ADAPTER_STATE_OFF;
+ break;
+
+ case BT_STATE_ON:
+ state_ = ADAPTER_STATE_ON;
+ break;
+
+ default:
+ NOTREACHED();
+ }
+
+ NotifyAdapterStateChanged(prev_state, GetState());
+}
+
+void Adapter::AdapterPropertiesCallback(bt_status_t status,
+ int num_properties,
+ bt_property_t* properties) {
+ LOG(INFO) << "Adapter properties changed";
+
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "status: " << BtStatusText(status);
+ return;
+ }
+
+ for (int i = 0; i < num_properties; i++) {
+ bt_property_t* property = properties + i;
+ switch (property->type) {
+ case BT_PROPERTY_BDADDR: {
+ std::string address = BtAddrString(reinterpret_cast<bt_bdaddr_t*>(
+ property->val));
+ LOG(INFO) << "Adapter address changed: " << address;
+ address_.Set(address);
+ break;
+ }
+ case BT_PROPERTY_BDNAME: {
+ bt_bdname_t* hal_name = reinterpret_cast<bt_bdname_t*>(property->val);
+ std::string name = reinterpret_cast<char*>(hal_name->name);
+ LOG(INFO) << "Adapter name changed: " << name;
+ name_.Set(name);
+ break;
+ }
+ default:
+ VLOG(1) << "Unhandled adapter property: "
+ << BtPropertyText(property->type);
+ break;
+ }
+
+ // TODO(armansito): notify others of the updated properties
+ }
+}
+
+bool Adapter::SetAdapterProperty(bt_property_type_t type,
+ void* value, int length) {
+ CHECK(length > 0);
+ CHECK(value);
+
+ bt_property_t property;
+ property.len = length;
+ property.val = value;
+ property.type = type;
+
+ int status = hal::BluetoothInterface::Get()->GetHALInterface()->
+ set_adapter_property(&property);
+ if (status != BT_STATUS_SUCCESS) {
+ VLOG(1) << "Failed to set property";
+ return false;
+ }
+
+ return true;
+}
+
+void Adapter::NotifyAdapterStateChanged(AdapterState prev_state,
+ AdapterState new_state) {
+ if (prev_state == new_state)
+ return;
+
+ std::lock_guard<std::mutex> lock(observers_lock_);
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnAdapterStateChanged(this, prev_state, new_state));
+}
+
+} // namespace bluetooth
--- /dev/null
+//
+// 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
+
+#include <atomic>
+#include <mutex>
+#include <string>
+
+#include <base/macros.h>
+#include <base/observer_list.h>
+
+#include "service/adapter_state.h"
+#include "service/hal/bluetooth_interface.h"
+#include "service/util/atomic_string.h"
+
+namespace bluetooth {
+
+// Represents the local Bluetooth adapter.
+class Adapter : hal::BluetoothInterface::Observer {
+ public:
+ // The default values returned before the Adapter is fully initialized and
+ // powered. The complete values for these fields are obtained following a
+ // successful call to "Enable".
+ static const char kDefaultAddress[];
+ static const char kDefaultName[];
+
+ // Observer interface allows other classes to receive notifications from us.
+ // All of the methods in this interface are declared as optional to allow
+ // different layers to process only those events that they are interested in.
+ class Observer {
+ public:
+ virtual ~Observer() = default;
+
+ virtual void OnAdapterStateChanged(Adapter* adapter,
+ AdapterState prev_state,
+ AdapterState new_state);
+ };
+
+ Adapter();
+ ~Adapter() override;
+
+ // Add or remove an observer.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Returns the current Adapter state.
+ AdapterState GetState() const;
+
+ // Returns true, if the adapter radio is current powered.
+ bool IsEnabled() const;
+
+ // Enables Bluetooth. This method will send a request to the Bluetooth adapter
+ // to power up its radio. Returns true, if the request was successfully sent
+ // to the controller, otherwise returns false. A successful call to this
+ // method only means that the enable request has been sent to the Bluetooth
+ // controller and does not imply that the operation itself succeeded.
+ bool Enable();
+
+ // Powers off the Bluetooth radio. Returns true, if the disable request was
+ // successfully sent to the Bluetooth controller.
+ bool Disable();
+
+ // Returns the name currently assigned to the local adapter.
+ std::string GetName() const;
+
+ // Sets the name assigned to the local Bluetooth adapter. This is the name
+ // that the local controller will present to remote devices.
+ bool SetName(const std::string& name);
+
+ // Returns the local adapter addess in string form (XX:XX:XX:XX:XX:XX).
+ std::string GetAddress() const;
+
+ private:
+ // hal::BluetoothInterface::Observer overrides.
+ void AdapterStateChangedCallback(bt_state_t state) override;
+ void AdapterPropertiesCallback(bt_status_t status,
+ int num_properties,
+ bt_property_t* properties) override;
+
+ // Sends a request to set the given HAL adapter property type and value.
+ bool SetAdapterProperty(bt_property_type_t type, void* value, int length);
+
+ // Helper for invoking observer method.
+ void NotifyAdapterStateChanged(AdapterState prev_state,
+ AdapterState new_state);
+
+ // The current adapter state.
+ std::atomic<AdapterState> state_;
+
+ // The Bluetooth device address of the local adapter in string from
+ // (i.e.. XX:XX:XX:XX:XX:XX)
+ util::AtomicString address_;
+
+ // The current local adapter name.
+ util::AtomicString name_;
+
+ // List of observers that are interested in notifications from us.
+ std::mutex observers_lock_;
+ base::ObserverList<Observer> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(Adapter);
+};
+
+} // namespace bluetooth
--- /dev/null
+//
+// 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.
+//
+
+#include "service/adapter_state.h"
+
+namespace bluetooth {
+
+std::string AdapterStateToString(AdapterState state) {
+ switch (state) {
+ case ADAPTER_STATE_DISCONNECTED:
+ return "ADAPTER_STATE_DISCONNECTED";
+ case ADAPTER_STATE_CONNECTING:
+ return "ADAPTER_STATE_CONNECTING";
+ case ADAPTER_STATE_CONNECTED:
+ return "ADAPTER_STATE_CONNECTED";
+ case ADAPTER_STATE_DISCONNECTING:
+ return "ADAPTER_STATE_DISCONNECTING";
+ case ADAPTER_STATE_OFF:
+ return "ADAPTER_STATE_OFF";
+ case ADAPTER_STATE_TURNING_ON:
+ return "ADAPTER_STATE_TURNING_ON";
+ case ADAPTER_STATE_ON:
+ return "ADAPTER_STATE_ON";
+ case ADAPTER_STATE_TURNING_OFF:
+ return "ADAPTER_STATE_TURNING_OFF";
+ default:
+ return "unknown state";
+ }
+}
+
+} // namespace bluetooth
--- /dev/null
+//
+// 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
+
+#include <string>
+
+namespace bluetooth {
+
+// Possible Adapter states. The values for each enumration have been copied
+// from frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java.
+// These values need to match their android.bluetooth.BluetoothAdapter
+// counterparts for this to be compatible with the framework, hence we
+// redeclare them here.
+enum AdapterState {
+ ADAPTER_STATE_DISCONNECTED = 0,
+ ADAPTER_STATE_CONNECTING = 1,
+ ADAPTER_STATE_CONNECTED = 2,
+ ADAPTER_STATE_DISCONNECTING = 3,
+ ADAPTER_STATE_OFF = 10,
+ ADAPTER_STATE_TURNING_ON = 11,
+ ADAPTER_STATE_ON = 12,
+ ADAPTER_STATE_TURNING_OFF = 13,
+ ADAPTER_STATE_INVALID = 0xFFFF
+};
+
+// Returns a string for the given Adapter state |state|.
+std::string AdapterStateToString(AdapterState state);
+
+} // namespace bluetooth
--- /dev/null
+//
+// 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.
+//
+
+#include <iostream>
+#include <string>
+
+#include <base/logging.h>
+#include <base/macros.h>
+#include <base/strings/string_split.h>
+#include <base/strings/string_util.h>
+#include <binder/ProcessState.h>
+
+#include "service/adapter_state.h"
+#include "service/ipc/binder/IBluetooth.h"
+#include "service/ipc/binder/IBluetoothCallback.h"
+
+using namespace std;
+
+using android::sp;
+
+using ipc::binder::IBluetooth;
+
+namespace {
+
+#define COLOR_OFF "\x1B[0m"
+#define COLOR_RED "\x1B[0;91m"
+#define COLOR_GREEN "\x1B[0;92m"
+#define COLOR_YELLOW "\x1B[0;93m"
+#define COLOR_BLUE "\x1B[0;94m"
+#define COLOR_MAGENTA "\x1B[0;95m"
+#define COLOR_BOLDGRAY "\x1B[1;30m"
+#define COLOR_BOLDWHITE "\x1B[1;37m"
+#define COLOR_BOLDYELLOW "\x1B[1;93m"
+
+const char kCommandDisable[] = "disable";
+const char kCommandEnable[] = "enable";
+const char kCommandGetState[] = "get-state";
+const char kCommandIsEnabled[] = "is-enabled";
+
+#define CHECK_ARGS_COUNT(args, op, num, msg) \
+ if (!(args.size() op num)) { \
+ PrintError(msg); \
+ return; \
+ }
+#define CHECK_NO_ARGS(args) \
+ CHECK_ARGS_COUNT(args, ==, 0, "Expected no arguments")
+
+// TODO(armansito): Clean up this code. Right now everything is in this
+// monolithic file. We should organize this into different classes for command
+// handling, console output/printing, callback handling, etc.
+// (See http://b/23387611)
+
+// Used to synchronize the printing of the command-line prompt and incoming
+// Binder callbacks.
+std::atomic_bool showing_prompt(false);
+
+void PrintPrompt() {
+ cout << COLOR_BLUE "[FCLI] " COLOR_OFF << flush;
+}
+
+class CLIBluetoothCallback : public ipc::binder::BnBluetoothCallback {
+ public:
+ CLIBluetoothCallback() = default;
+ ~CLIBluetoothCallback() override = default;
+
+ // IBluetoothCallback override:
+ void OnBluetoothStateChange(
+ bluetooth::AdapterState prev_state,
+ bluetooth::AdapterState new_state) override {
+ if (showing_prompt.load())
+ cout << endl;
+ cout << COLOR_BOLDWHITE "Adapter state changed: " COLOR_OFF
+ << COLOR_MAGENTA << AdapterStateToString(prev_state) << COLOR_OFF
+ << COLOR_BOLDWHITE " -> " COLOR_OFF
+ << COLOR_BOLDYELLOW << AdapterStateToString(new_state) << COLOR_OFF
+ << endl << endl;
+ if (showing_prompt.load())
+ PrintPrompt();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CLIBluetoothCallback);
+};
+
+void PrintError(const string& message) {
+ cout << COLOR_RED << message << COLOR_OFF << endl;
+}
+
+void PrintCommandStatus(bool status) {
+ cout << COLOR_BOLDWHITE "Command status: " COLOR_OFF
+ << (status ? (COLOR_GREEN "success") : (COLOR_RED "failure"))
+ << COLOR_OFF << endl << endl;
+}
+
+void PrintFieldAndValue(const string& field, const string& value) {
+ cout << COLOR_BOLDWHITE << field << ": " << COLOR_BOLDYELLOW << value
+ << COLOR_OFF << endl;
+}
+
+void PrintFieldAndBoolValue(const string& field, bool value) {
+ PrintFieldAndValue(field, (value ? "true" : "false"));
+}
+
+void HandleDisable(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+ PrintCommandStatus(bt_iface->Disable());
+}
+
+void HandleEnable(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+ PrintCommandStatus(bt_iface->Enable());
+}
+
+void HandleGetState(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+ bluetooth::AdapterState state = static_cast<bluetooth::AdapterState>(
+ bt_iface->GetState());
+ PrintFieldAndValue("Adapter state", bluetooth::AdapterStateToString(state));
+}
+
+void HandleIsEnabled(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+ bool enabled = bt_iface->IsEnabled();
+ PrintFieldAndBoolValue("Adapter enabled", enabled);
+}
+
+void HandleGetLocalAddress(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+ string address = bt_iface->GetAddress();
+ PrintFieldAndValue("Adapter address", address);
+}
+
+void HandleSetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_ARGS_COUNT(args, >=, 1, "No name was given");
+
+ std::string name;
+ for (const auto& arg : args)
+ name += arg + " ";
+
+ base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &name);
+
+ PrintCommandStatus(bt_iface->SetName(name));
+}
+
+void HandleGetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+ string name = bt_iface->GetName();
+ PrintFieldAndValue("Adapter name", name);
+}
+
+void HandleAdapterInfo(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ cout << COLOR_BOLDWHITE "Adapter Properties: " COLOR_OFF << endl;
+
+ PrintFieldAndValue("\tAddress", bt_iface->GetAddress());
+ PrintFieldAndValue("\tState", bluetooth::AdapterStateToString(
+ static_cast<bluetooth::AdapterState>(bt_iface->GetState())));
+ PrintFieldAndValue("\tName", bt_iface->GetName());
+}
+
+void HandleHelp(IBluetooth* bt_iface, const vector<string>& args);
+
+struct {
+ string command;
+ void (*func)(IBluetooth*, const vector<string>& args);
+ string help;
+} kCommandMap[] = {
+ { "help", HandleHelp, "\t\t\tDisplay this message" },
+ { "disable", HandleDisable, "\t\t\tDisable Bluetooth" },
+ { "enable", HandleEnable, "\t\t\tEnable Bluetooth" },
+ { "get-state", HandleGetState, "\t\tGet the current adapter state" },
+ { "is-enabled", HandleIsEnabled, "\t\tReturn if Bluetooth is enabled" },
+ { "get-local-address", HandleGetLocalAddress,
+ "\tGet the local adapter address" },
+ { "set-local-name", HandleSetLocalName, "\t\tSet the local adapter name" },
+ { "get-local-name", HandleGetLocalName, "\t\tGet the local adapter name" },
+ { "adapter-info", HandleAdapterInfo, "\t\tPrint adapter properties" },
+ {},
+};
+
+void HandleHelp(IBluetooth* /* bt_iface */, const vector<string>& /* args */) {
+ cout << endl;
+ for (int i = 0; kCommandMap[i].func; i++)
+ cout << "\t" << kCommandMap[i].command << kCommandMap[i].help << endl;
+ cout << endl;
+}
+
+} // namespace
+
+int main() {
+ sp<IBluetooth> bt_iface = IBluetooth::getClientInterface();
+ if (!bt_iface.get()) {
+ LOG(ERROR) << "Failed to obtain handle on IBluetooth";
+ return EXIT_FAILURE;
+ }
+
+ // Initialize the Binder process thread pool. We have to set this up,
+ // otherwise, incoming callbacks from IBluetoothCallback will block the main
+ // thread (in other words, we have to do this as we are a "Binder server").
+ android::ProcessState::self()->startThreadPool();
+
+ // Register Adapter state-change callback
+ sp<CLIBluetoothCallback> callback = new CLIBluetoothCallback();
+ bt_iface->RegisterCallback(callback);
+
+ cout << COLOR_BOLDWHITE << "Fluoride Command-Line Interface\n" << COLOR_OFF
+ << endl
+ << "Type \"help\" to see possible commands.\n"
+ << endl;
+
+ while (true) {
+ string command;
+
+ PrintPrompt();
+
+ showing_prompt = true;
+ getline(cin, command);
+ showing_prompt = false;
+
+ vector<string> args;
+ base::SplitString(command, ' ', &args);
+
+ if (args.empty())
+ continue;
+
+ // The first argument is the command while the remaning are what we pass to
+ // the handler functions.
+ command = args[0];
+ args.erase(args.begin());
+
+ bool command_handled = false;
+ for (int i = 0; kCommandMap[i].func && !command_handled; i++) {
+ if (command == kCommandMap[i].command) {
+ kCommandMap[i].func(bt_iface.get(), args);
+ command_handled = true;
+ }
+ }
+
+ if (!command_handled)
+ cout << "Unrecognized command: " << command << endl;
+ }
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+//
+// 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.
+//
+
+#include "service/daemon.h"
+
+#include <memory>
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+#include "service/hal/bluetooth_interface.h"
+#include "service/ipc/ipc_manager.h"
+#include "service/settings.h"
+
+namespace bluetooth {
+
+namespace {
+
+// The global Daemon instance.
+Daemon* g_daemon = nullptr;
+
+class DaemonImpl : public Daemon {
+ public:
+ DaemonImpl() : initialized_(false) {
+ }
+
+ ~DaemonImpl() override {
+ if (!initialized_)
+ return;
+
+ CleanUpBluetoothStack();
+ }
+
+ void StartMainLoop() override {
+ message_loop_->Run();
+ }
+
+ Settings* GetSettings() const override {
+ return settings_.get();
+ }
+
+ base::MessageLoop* GetMessageLoop() const override {
+ return message_loop_.get();
+ }
+
+ private:
+ void CleanUpBluetoothStack() {
+ // The Adapter object needs to be cleaned up before the HAL interfaces.
+ ipc_manager_.reset();
+ adapter_.reset();
+ hal::BluetoothInterface::CleanUp();
+ }
+
+ bool SetUpIPC() {
+ // If an IPC socket path was given, initialize IPC with it. Otherwise
+ // initialize Binder IPC.
+ if (settings_->UseSocketIPC()) {
+ if (!ipc_manager_->Start(ipc::IPCManager::TYPE_UNIX, nullptr)) {
+ LOG(ERROR) << "Failed to set up UNIX domain-socket IPCManager";
+ return false;
+ }
+ } else if (!ipc_manager_->Start(ipc::IPCManager::TYPE_BINDER, nullptr)) {
+ LOG(ERROR) << "Failed to set up Binder IPCManager";
+ return false;
+ }
+
+ return true;
+ }
+
+ bool Init() override {
+ CHECK(!initialized_);
+ message_loop_.reset(new base::MessageLoop());
+
+ settings_.reset(new Settings());
+ if (!settings_->Init()) {
+ LOG(ERROR) << "Failed to set up Settings";
+ return false;
+ }
+
+ if (!hal::BluetoothInterface::Initialize()) {
+ LOG(ERROR) << "Failed to set up BluetoothInterface";
+ return false;
+ }
+
+ adapter_.reset(new Adapter());
+ ipc_manager_.reset(new ipc::IPCManager(adapter_.get()));
+
+ if (!SetUpIPC()) {
+ CleanUpBluetoothStack();
+ return false;
+ }
+
+ initialized_ = true;
+ LOG(INFO) << "Daemon initialized";
+
+ return true;
+ }
+
+ bool initialized_;
+ std::unique_ptr<base::MessageLoop> message_loop_;
+ std::unique_ptr<Settings> settings_;
+ std::unique_ptr<Adapter> adapter_;
+ std::unique_ptr<ipc::IPCManager> ipc_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(DaemonImpl);
+};
+
+} // namespace
+
+// static
+bool Daemon::Initialize() {
+ CHECK(!g_daemon);
+
+ g_daemon = new DaemonImpl();
+ if (g_daemon->Init())
+ return true;
+
+ LOG(ERROR) << "Failed to initialize the Daemon object";
+
+ delete g_daemon;
+ g_daemon = nullptr;
+
+ return false;
+}
+
+// static
+void Daemon::ShutDown() {
+ CHECK(g_daemon);
+ delete g_daemon;
+ g_daemon = nullptr;
+}
+
+// static
+void Daemon::InitializeForTesting(Daemon* test_daemon) {
+ CHECK(test_daemon);
+ CHECK(!g_daemon);
+
+ g_daemon = test_daemon;
+}
+
+// static
+Daemon* Daemon::Get() {
+ CHECK(g_daemon);
+ return g_daemon;
+}
+
+} // namespace bluetooth
--- /dev/null
+//
+// 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
+
+#include <base/macros.h>
+#include <base/message_loop/message_loop.h>
+
+namespace ipc {
+class IPCManager;
+} // namespace ipc
+
+namespace bluetooth {
+
+class CoreStack;
+class Settings;
+
+// The Daemon class is a singleton that represents the root of the ownership
+// hierarchy. The single instance sets up and owns the main event loop, the IPC
+// handlers, global Settings, and the core Bluetooth stack.
+class Daemon {
+ public:
+ // Initializes the daemon. This must be called to at the start of the
+ // application to set up the global daemon instance and everything it manages.
+ // Returns false in case of a failure.
+ static bool Initialize();
+
+ // Cleans up all the resources associated with the global Daemon object.
+ static void ShutDown();
+
+ // Assigns the global Daemon instance for testing. Should only be called from
+ // test code.
+ static void InitializeForTesting(Daemon* test_daemon);
+
+ // Returns the singleton Daemon instance. All classes can interact with the
+ // Daemon, obtain its resources etc using this getter.
+ static Daemon* Get();
+
+ // The global Settings object. All classes have direct access to this through
+ // the Daemon object.
+ virtual Settings* GetSettings() const = 0;
+
+ // The main event loop. This should be used for any events and delayed tasks
+ // that should be executed on the daemon's main thread.
+ virtual base::MessageLoop* GetMessageLoop() const = 0;
+
+ // Starts the daemon's main loop.
+ virtual void StartMainLoop() = 0;
+
+ protected:
+ Daemon() = default;
+ virtual ~Daemon() = default;
+
+ private:
+ // Internal instance helper called by Initialize().
+ virtual bool Init() = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(Daemon);
+};
+
+} // namespace bluetooth
--- /dev/null
+//
+// 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 "bt_gatts"
+
+#include "gatt_server.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <array>
+#include <condition_variable>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "service/hal/bluetooth_interface.h"
+#include "service/logging_helpers.h"
+#include "service/uuid.h"
+
+extern "C" {
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+} // extern "C"
+
+namespace {
+
+const size_t kMaxGattAttributeSize = 512;
+// TODO(icoolidge): Difficult to generalize without knowing how many attributes.
+const int kNumBlueDroidHandles = 60;
+
+// TODO(icoolidge): Support multiple instances
+// 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 };
+
+} // namespace
+
+namespace bluetooth {
+namespace gatt {
+
+struct Characteristic {
+ UUID uuid;
+ int blob_section;
+ std::vector<uint8_t> blob;
+
+ // Support synchronized blob updates by latching under mutex.
+ std::vector<uint8_t> next_blob;
+ bool next_blob_pending;
+ bool notify;
+};
+
+struct ServerInternals {
+ ServerInternals();
+ ~ServerInternals();
+ int Initialize();
+ 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;
+
+ // The attribute cache, indexed by BlueDroid handles.
+ std::unordered_map<int, Characteristic> characteristics;
+
+ // Associate a control attribute with its value attribute.
+ std::unordered_map<int, int> controlled_blobs;
+
+ ScanResults scan_results;
+
+ UUID last_write;
+ const btgatt_interface_t *gatt;
+ int server_if;
+ int client_if;
+ int service_handle;
+ btgatt_srvc_id_t service_id;
+ std::set<int> connections;
+
+ std::mutex lock;
+ std::condition_variable api_synchronize;
+ int pipefd[kPipeNumEnds];
+};
+
+} // namespace gatt
+} // namespace bluetooth
+
+namespace {
+
+/** Callback invoked in response to register_server */
+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);
+
+ 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;
+
+ g_internal->gatt->server->add_service(
+ server_if, &service_id, kNumBlueDroidHandles);
+}
+
+void ServiceAddedCallback(int status, int server_if, btgatt_srvc_id_t *srvc_id,
+ int srvc_handle) {
+ 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(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.
+ 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(g_internal->lock);
+
+ 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 &&
+ ch.blob_section == 0) {
+ std::swap(ch.blob, ch.next_blob);
+ ch.next_blob_pending = false;
+ }
+
+ const size_t blob_offset_octets =
+ std::min(ch.blob.size(), ch.blob_section * kMaxGattAttributeSize);
+ const size_t blob_remaining = ch.blob.size() - blob_offset_octets;
+ const size_t attribute_size = std::min(kMaxGattAttributeSize, blob_remaining);
+
+ std::string addr(BtAddrString(bda));
+ LOG_INFO(LOG_TAG,
+ "%s: connection:%d (%s) reading attr:%d attribute_offset_octets:%d "
+ "blob_section:%u (is_long:%u)",
+ __func__, conn_id, addr.c_str(), attr_handle, attribute_offset_octets,
+ ch.blob_section, is_long);
+
+ btgatt_response_t response;
+ response.attr_value.len = 0;
+
+ if (attribute_offset_octets < static_cast<int>(attribute_size)) {
+ std::copy(ch.blob.begin() + blob_offset_octets + attribute_offset_octets,
+ ch.blob.begin() + blob_offset_octets + attribute_size,
+ response.attr_value.value);
+ response.attr_value.len = attribute_size - attribute_offset_octets;
+ }
+
+ response.attr_value.handle = attr_handle;
+ response.attr_value.offset = attribute_offset_octets;
+ response.attr_value.auth_req = 0;
+ g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+}
+
+void RequestWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
+ int attr_handle, int attribute_offset, int length,
+ bool need_rsp, bool is_prep, uint8_t *value) {
+ std::string addr(BtAddrString(bda));
+ LOG_INFO(LOG_TAG,
+ "%s: connection:%d (%s:trans:%d) write attr:%d attribute_offset:%d "
+ "length:%d "
+ "need_resp:%u is_prep:%u",
+ __func__, conn_id, addr.c_str(), trans_id, attr_handle, attribute_offset,
+ length, need_rsp, is_prep);
+
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+
+ 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 = g_internal->controlled_blobs.find(attr_handle);
+ // If this is a control attribute, adjust offset of the target blob.
+ 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(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.
+ g_internal->last_write = ch.uuid;
+ }
+
+ // Respond only if needed.
+ if (!need_rsp) return;
+
+ btgatt_response_t response;
+ response.attr_value.handle = attr_handle;
+ response.attr_value.offset = attribute_offset;
+ response.attr_value.len = length;
+ response.attr_value.auth_req = 0;
+ // 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);
+ g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+}
+
+void RequestExecWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
+ int exec_write) {
+ std::string addr(BtAddrString(bda));
+ LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__,
+ conn_id, addr.c_str(), trans_id, exec_write);
+
+ // This 'response' data is unused for ExecWriteResponses.
+ // It is only used to pass BlueDroid argument validation.
+ btgatt_response_t response = {};
+ g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+
+ if (!exec_write)
+ return;
+
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+ // Communicate the attribute UUID as notification of a write update.
+ const bluetooth::UUID::UUID128Bit uuid =
+ 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));
+}
+
+void ConnectionCallback(int conn_id, int server_if, int connected,
+ bt_bdaddr_t *bda) {
+ std::string addr(BtAddrString(bda));
+ 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) {
+ g_internal->connections.insert(conn_id);
+ } else if (connected == 0) {
+ 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__,
+ status, server_if, srvc_handle, char_handle);
+
+ bluetooth::UUID id(*uuid);
+
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+
+ 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.
+ g_internal->api_synchronize.notify_one();
+}
+
+void DescriptorAddedCallback(int status, int server_if, bt_uuid_t *uuid,
+ int srvc_handle, int descr_handle) {
+ LOG_INFO(LOG_TAG,
+ "%s: status:%d server_if:%d service_handle:%d uuid[0]:%u "
+ "descr_handle:%d",
+ __func__, status, server_if, srvc_handle, uuid->uu[0], descr_handle);
+}
+
+void ServiceStartedCallback(int status, int server_if, int srvc_handle) {
+ LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
+ status, server_if, 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 = g_internal->service_id.id.uuid;
+ ++client_id.uu[15];
+
+ 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__);
+ }
+}
+
+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]);
+ g_internal->client_if = client_if;
+
+ // Setup our advertisement. This has no callback.
+ bt_status_t btstat = g_internal->gatt->client->set_adv_data(
+ client_if, false, /* beacon, not scan response */
+ false, /* name */
+ false, /* no txpower */
+ 2, 2, /* interval */
+ 0, /* appearance */
+ 0, nullptr, /* no mfg data */
+ 0, nullptr, /* no service data */
+ 0, nullptr /* no service id yet */);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to set advertising data");
+ return;
+ }
+
+ // TODO(icoolidge): Deprecated, use multi-adv interface.
+ // This calls back to ListenCallback.
+ btstat = g_internal->gatt->client->listen(client_if, true);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to start listening");
+ }
+}
+
+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(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__,
+ status, server_if, srvc_handle);
+ // This terminates a Stop call.
+ // TODO(icoolidge): make this symmetric with start
+ 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(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__,
+ conn_id, status, client_if, addr.c_str());
+}
+
+void ClientDisconnectCallback(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__,
+ conn_id, status, client_if, addr.c_str());
+}
+
+void IndicationSentCallback(UNUSED_ATTR int conn_id,
+ UNUSED_ATTR int status) {
+ // TODO(icoolidge): what to do
+}
+
+void ResponseConfirmationCallback(UNUSED_ATTR int status,
+ UNUSED_ATTR int handle) {
+ // TODO(icoolidge): what to do
+}
+
+const btgatt_server_callbacks_t gatt_server_callbacks = {
+ RegisterServerCallback,
+ ConnectionCallback,
+ ServiceAddedCallback,
+ nullptr, /* included_service_added_cb */
+ CharacteristicAddedCallback,
+ DescriptorAddedCallback,
+ ServiceStartedCallback,
+ ServiceStoppedCallback,
+ nullptr, /* service_deleted_cb */
+ RequestReadCallback,
+ RequestWriteCallback,
+ RequestExecWriteCallback,
+ ResponseConfirmationCallback,
+ IndicationSentCallback,
+ nullptr, /* congestion_cb*/
+ nullptr, /* mtu_changed_cb */
+};
+
+// TODO(eisenbach): Refactor GATT interface to not require servers
+// to refer to the client interface.
+const btgatt_client_callbacks_t gatt_client_callbacks = {
+ RegisterClientCallback,
+ ScanResultCallback,
+ ClientConnectCallback,
+ ClientDisconnectCallback,
+ nullptr, /* search_complete_cb; */
+ nullptr, /* search_result_cb; */
+ nullptr, /* get_characteristic_cb; */
+ nullptr, /* get_descriptor_cb; */
+ nullptr, /* get_included_service_cb; */
+ nullptr, /* register_for_notification_cb; */
+ nullptr, /* notify_cb; */
+ nullptr, /* read_characteristic_cb; */
+ nullptr, /* write_characteristic_cb; */
+ nullptr, /* read_descriptor_cb; */
+ nullptr, /* write_descriptor_cb; */
+ nullptr, /* execute_write_cb; */
+ nullptr, /* read_remote_rssi_cb; */
+ ListenCallback,
+ nullptr, /* configure_mtu_cb; */
+ nullptr, /* scan_filter_cfg_cb; */
+ nullptr, /* scan_filter_param_cb; */
+ nullptr, /* scan_filter_status_cb; */
+ nullptr, /* multi_adv_enable_cb */
+ nullptr, /* multi_adv_update_cb; */
+ nullptr, /* multi_adv_data_cb*/
+ nullptr, /* multi_adv_disable_cb; */
+ nullptr, /* congestion_cb; */
+ nullptr, /* batchscan_cfg_storage_cb; */
+ nullptr, /* batchscan_enb_disable_cb; */
+ nullptr, /* batchscan_reports_cb; */
+ nullptr, /* batchscan_threshold_cb; */
+ nullptr, /* track_adv_event_cb; */
+ nullptr, /* scan_parameter_setup_completed_cb; */
+};
+
+const btgatt_callbacks_t gatt_callbacks = {
+ /** Set to sizeof(btgatt_callbacks_t) */
+ sizeof(btgatt_callbacks_t),
+
+ /** GATT Client callbacks */
+ &gatt_client_callbacks,
+
+ /** GATT Server callbacks */
+ &gatt_server_callbacks};
+
+} // namespace
+
+namespace bluetooth {
+namespace gatt {
+
+int ServerInternals::Initialize() {
+ // Get the interface to the GATT profile.
+ const bt_interface_t* bt_iface =
+ hal::BluetoothInterface::Get()->GetHALInterface();
+ gatt = reinterpret_cast<const btgatt_interface_t *>(
+ bt_iface->get_profile_interface(BT_PROFILE_GATT_ID));
+ if (!gatt) {
+ LOG_ERROR(LOG_TAG, "Error getting GATT interface");
+ return -1;
+ }
+
+ bt_status_t btstat = gatt->init(&gatt_callbacks);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface");
+ return -1;
+ }
+
+ int status = pipe(pipefd);
+ if (status == -1) {
+ LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno));
+ return -1;
+ }
+
+ 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),
+ client_if(0),
+ service_handle(0),
+ pipefd{INVALID_FD, INVALID_FD} {}
+
+ServerInternals::~ServerInternals() {
+ if (pipefd[0] != INVALID_FD)
+ close(pipefd[0]);
+ if (pipefd[1] != INVALID_FD)
+ close(pipefd[1]);
+
+ gatt->server->delete_service(server_if, service_handle);
+ gatt->server->unregister_server(server_if);
+ gatt->client->unregister_client(client_if);
+}
+
+Server::Server() : internal_(nullptr) {}
+
+Server::~Server() {}
+
+bool Server::Initialize(const UUID& service_id, int* gatt_pipe) {
+ internal_.reset(new ServerInternals);
+ if (!internal_) {
+ LOG_ERROR(LOG_TAG, "Error creating internals");
+ return false;
+ }
+ g_internal = internal_.get();
+
+ std::unique_lock<std::mutex> lock(internal_->lock);
+ int status = internal_->Initialize();
+ if (status) {
+ LOG_ERROR(LOG_TAG, "Error initializing internals");
+ return false;
+ }
+
+ bt_uuid_t uuid = service_id.GetBlueDroid();
+
+ bt_status_t btstat = internal_->gatt->server->register_server(&uuid);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to register server");
+ return false;
+ }
+
+ internal_->api_synchronize.wait(lock);
+ // TODO(icoolidge): Better error handling.
+ if (internal_->server_if == 0) {
+ LOG_ERROR(LOG_TAG, "Initialization of server failed");
+ return false;
+ }
+
+ *gatt_pipe = internal_->pipefd[kPipeReadEnd];
+ LOG_INFO(LOG_TAG, "Server Initialize succeeded");
+ return true;
+}
+
+bool Server::SetAdvertisement(const std::vector<UUID>& ids,
+ const std::vector<uint8_t>& service_data,
+ const std::vector<uint8_t>& manufacturer_data,
+ bool transmit_name) {
+ std::vector<uint8_t> id_data;
+ auto mutable_manufacturer_data = manufacturer_data;
+ auto mutable_service_data = service_data;
+
+ for (const UUID &id : ids) {
+ const auto le_id = id.GetFullLittleEndian();
+ id_data.insert(id_data.end(), le_id.begin(), le_id.end());
+ }
+
+ 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(
+ internal_->client_if, false, /* beacon, not scan response */
+ transmit_name, /* name */
+ false, /* no txpower */
+ 2, 2, /* interval */
+ 0, /* appearance */
+ mutable_manufacturer_data.size(),
+ reinterpret_cast<char *>(mutable_manufacturer_data.data()),
+ mutable_service_data.size(),
+ reinterpret_cast<char *>(mutable_service_data.data()), id_data.size(),
+ reinterpret_cast<char *>(id_data.data()));
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to set advertising data");
+ return false;
+ }
+ return true;
+}
+
+bool Server::SetScanResponse(const std::vector<UUID>& ids,
+ const std::vector<uint8_t>& service_data,
+ const std::vector<uint8_t>& manufacturer_data,
+ bool transmit_name) {
+ std::vector<uint8_t> id_data;
+ auto mutable_manufacturer_data = manufacturer_data;
+ auto mutable_service_data = service_data;
+
+ for (const UUID &id : ids) {
+ const auto le_id = id.GetFullLittleEndian();
+ id_data.insert(id_data.end(), le_id.begin(), le_id.end());
+ }
+
+ 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(
+ internal_->client_if, true, /* scan response */
+ transmit_name, /* name */
+ false, /* no txpower */
+ 2, 2, /* interval */
+ 0, /* appearance */
+ mutable_manufacturer_data.size(),
+ reinterpret_cast<char *>(mutable_manufacturer_data.data()),
+ mutable_service_data.size(),
+ reinterpret_cast<char *>(mutable_service_data.data()), id_data.size(),
+ reinterpret_cast<char *>(id_data.data()));
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to set scan response data");
+ return false;
+ }
+ return true;
+}
+
+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;
+ return true;
+}
+
+bool Server::AddBlob(const UUID &id, const UUID &control_id, int properties,
+ int permissions) {
+ std::unique_lock<std::mutex> lock(internal_->lock);
+
+ // First, add the primary attribute (characteristic value)
+ 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.
+ btstat = internal_->AddCharacteristic(
+ control_id,
+ kPropertyRead | kPropertyWrite,
+ kPermissionRead | kPermissionWrite);
+ 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;
+
+ Characteristic &ctrl = internal_->characteristics[control_attribute];
+ ctrl.next_blob.clear();
+ ctrl.next_blob.push_back(0);
+ ctrl.next_blob_pending = true;
+ ctrl.blob_section = 0;
+ ctrl.notify = false;
+ return true;
+}
+
+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;
+}
+
+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;
+}
+
+bool Server::ScanEnable() {
+ bt_status_t btstat = internal_->gatt->client->scan(true);
+ if (btstat) {
+ LOG_ERROR(LOG_TAG, "Enable scan failed: %d", btstat);
+ return false;
+ }
+ return true;
+}
+
+bool Server::ScanDisable() {
+ bt_status_t btstat = internal_->gatt->client->scan(false);
+ if (btstat) {
+ LOG_ERROR(LOG_TAG, "Disable scan failed: %d", btstat);
+ return false;
+ }
+ return true;
+}
+
+bool Server::GetScanResults(ScanResults *results) {
+ std::lock_guard<std::mutex> lock(internal_->lock);
+ *results = internal_->scan_results;
+ return true;
+}
+
+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];
+ ch.next_blob = value;
+ ch.next_blob_pending = true;
+
+ if (!ch.notify)
+ return true;
+
+ for (auto connection : internal_->connections) {
+ char dummy = 0;
+ internal_->gatt->server->send_indication(internal_->server_if,
+ attribute_id,
+ connection,
+ sizeof(dummy),
+ true,
+ &dummy);
+ }
+ return true;
+}
+
+bool Server::GetCharacteristicValue(const UUID &id, std::vector<uint8_t> *value) {
+ std::lock_guard<std::mutex> lock(internal_->lock);
+ const int attribute_id = internal_->uuid_to_attribute[id];
+ *value = internal_->characteristics[attribute_id].blob;
+ return true;
+}
+
+} // namespace gatt
+} // namespace bluetooth
--- /dev/null
+//
+// 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
+
+#include <array>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "hardware/bluetooth.h"
+#include "hardware/bt_gatt.h"
+#include "uuid.h"
+
+namespace bluetooth {
+namespace gatt {
+
+// Attribute permission values
+const int kPermissionRead = 0x1;
+const int kPermissionReadEncrypted = 0x2;
+const int kPermissionReadEncryptedMitm = 0x4;
+const int kPermissionWrite = 0x10;
+const int kPermissionWriteEnecrypted = 0x20;
+const int KPermissionWriteEncryptedMitm = 0x40;
+const int kPermissionWriteSigned = 0x80;
+const int kPermissionWriteSignedMitm = 0x100;
+
+// GATT characteristic properties bit-field values
+const int kPropertyBroadcast = 0x1;
+const int kPropertyRead = 0x2;
+const int kPropertyWriteNoResponse = 0x4;
+const int kPropertyWrite = 0x8;
+const int kPropertyNotify = 0x10;
+const int kPropertyIndicate = 0x20;
+const int kPropertySignedWrite = 0x40;
+const int kPropertyExtendedProps = 0x80;
+
+// A mapping from string bluetooth addresses to RSSI measurements.
+typedef std::unordered_map<std::string, int> ScanResults;
+
+// 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,
+// and synchronously read with 'GetCharacteristicValue'
+class Server {
+ public:
+ Server();
+ ~Server();
+
+ // Register GATT interface, initialize internal state,
+ // and open a pipe for characteristic write notification.
+ bool Initialize(const UUID& service_id, int* gatt_pipe);
+
+ // Control the content of service advertisement.
+ bool SetAdvertisement(const std::vector<UUID>& ids,
+ const std::vector<uint8_t>& service_data,
+ const std::vector<uint8_t>& manufacturer_data,
+ bool transmit_name);
+
+ // Control the content of service scan response.
+ bool SetScanResponse(const std::vector<UUID>& ids,
+ const std::vector<uint8_t>& service_data,
+ const std::vector<uint8_t>& manufacturer_data,
+ bool transmit_name);
+
+ // Add an ordinary characteristic for reading and/or writing.
+ bool AddCharacteristic(const UUID &id, int properties, int permissions);
+
+ // Add a special 'blob' characteristic with a corresponding control
+ // attribute to manipulate which part of the blob the attribute represents.
+ bool AddBlob(const UUID &id, const UUID &control_id, int properties,
+ int permissions);
+
+ // Put a new value into a characeteristic.
+ // It will be read from a client starting at the next 0-offset read.
+ bool SetCharacteristicValue(const UUID &id, const std::vector<uint8_t> &value);
+
+ // Get the current value of a characteristic.
+ bool GetCharacteristicValue(const UUID &id, std::vector<uint8_t> *value);
+
+ // Start this service. Activate advertisements, allow connections.
+ // Characteristics should all be created before this.
+ bool Start();
+
+ // Cease advertisements and disallow connections.
+ bool Stop();
+
+ // Enable LE scan. Scan results will be cached internally.
+ bool ScanEnable();
+
+ // Disable LE scan.
+ bool ScanDisable();
+
+ // Copy out the cached scan results.
+ bool GetScanResults(ScanResults *results);
+
+ private:
+ // Internal data.
+ std::unique_ptr<ServerInternals> internal_;
+};
+
+} // namespace gatt
+} // namespace bluetooth
--- /dev/null
+//
+// 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.
+//
+
+#include "service/hal/bluetooth_interface.h"
+
+#include <mutex>
+
+#include <base/logging.h>
+#include <base/observer_list.h>
+
+#include "service/logging_helpers.h"
+
+extern "C" {
+#include "btcore/include/hal_util.h"
+} // extern "C"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+// The global BluetoothInterface instance.
+BluetoothInterface* g_bluetooth_interface = nullptr;
+
+// Mutex used by callbacks to access |g_bluetooth_interface|. Since there is no
+// good way to unregister callbacks and since the global instance can be deleted
+// concurrently during shutdown, this lock is used.
+//
+// TODO(armansito): There should be a way to cleanly shut down the Bluetooth
+// stack.
+mutex g_instance_lock;
+
+// Helper for obtaining the observer list. This is forward declared here and
+// defined below since it depends on BluetoothInterfaceImpl.
+base::ObserverList<BluetoothInterface::Observer>* GetObservers();
+
+#define FOR_EACH_BLUETOOTH_OBSERVER(func) \
+ FOR_EACH_OBSERVER(BluetoothInterface::Observer, *GetObservers(), func)
+
+void AdapterStateChangedCallback(bt_state_t state) {
+ lock_guard<mutex> lock(g_instance_lock);
+ if (!g_bluetooth_interface) {
+ LOG(WARNING) << "Callback received after global instance was destroyed";
+ return;
+ }
+
+ VLOG(1) << "Adapter state changed: " << BtStateText(state);
+ FOR_EACH_BLUETOOTH_OBSERVER(AdapterStateChangedCallback(state));
+}
+
+void AdapterPropertiesCallback(bt_status_t status,
+ int num_properties,
+ bt_property_t* properties) {
+ lock_guard<mutex> lock(g_instance_lock);
+ if (!g_bluetooth_interface) {
+ LOG(WARNING) << "Callback received after global instance was destroyed";
+ return;
+ }
+
+ VLOG(1) << "Adapter properties changed - status: " << BtStatusText(status)
+ << ", num_properties: " << num_properties;
+ FOR_EACH_BLUETOOTH_OBSERVER(
+ AdapterPropertiesCallback(status, num_properties, properties));
+}
+
+void ThreadEventCallback(bt_cb_thread_evt evt) {
+ VLOG(1) << "ThreadEventCallback" << BtEventText(evt);
+
+ // TODO(armansito): This callback is completely useless to us but btif borks
+ // out if this is not set. Consider making this optional.
+}
+
+bool SetWakeAlarmCallout(uint64_t /* delay_millis */,
+ bool /* should_wake */,
+ alarm_cb /* cb */,
+ void* /* data */) {
+ // TODO(armansito): According to sharvil@, this interface doesn't even need to
+ // exist and can be done entirely from within osi by interfacing directly with
+ // the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
+ return false;
+}
+
+int AcquireWakeLockCallout(const char* /* lock_name */) {
+ // TODO(armansito): According to sharvil@, this interface doesn't even need to
+ // exist and can be done entirely from within osi by interfacing directly with
+ // the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
+ // Lie here and return success so that enabling and disabling the controller
+ // works before this is properly implemented.
+ return BT_STATUS_SUCCESS;
+}
+
+int ReleaseWakeLockCallout(const char* /* lock_name */) {
+ // TODO(armansito): According to sharvil@, this interface doesn't even need to
+ // exist and can be done entirely from within osi by interfacing directly with
+ // the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
+ // Lie here and return success so that enabling and disabling the controller
+ // works before this is properly implemented.
+ return BT_STATUS_SUCCESS;
+}
+
+// The HAL Bluetooth DM callbacks.
+bt_callbacks_t bt_callbacks = {
+ sizeof(bt_callbacks_t),
+ AdapterStateChangedCallback,
+ AdapterPropertiesCallback,
+ nullptr, /* remote_device_properties_cb */
+ nullptr, /* device_found_cb */
+ nullptr, /* discovery_state_changed_cb */
+ nullptr, /* pin_request_cb */
+ nullptr, /* ssp_request_cb */
+ nullptr, /* bond_state_changed_cb */
+ nullptr, /* acl_state_changed_cb */
+ ThreadEventCallback,
+ nullptr, /* dut_mode_recv_cb */
+ nullptr, /* le_test_mode_cb */
+ nullptr /* energy_info_cb */
+};
+
+bt_os_callouts_t bt_os_callouts = {
+ sizeof(bt_os_callouts_t),
+ SetWakeAlarmCallout,
+ AcquireWakeLockCallout,
+ ReleaseWakeLockCallout
+};
+
+} // namespace
+
+// BluetoothInterface implementation for production.
+class BluetoothInterfaceImpl : public BluetoothInterface {
+ public:
+ BluetoothInterfaceImpl()
+ : hal_iface_(nullptr),
+ hal_adapter_(nullptr) {
+ }
+
+ ~BluetoothInterfaceImpl() override {
+ hal_iface_->cleanup();
+ };
+
+ // BluetoothInterface overrides.
+ void AddObserver(Observer* observer) override {
+ lock_guard<mutex> lock(g_instance_lock);
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(Observer* observer) override {
+ lock_guard<mutex> lock(g_instance_lock);
+ observers_.RemoveObserver(observer);
+ }
+
+ const bt_interface_t* GetHALInterface() const override {
+ return hal_iface_;
+ }
+
+ const bluetooth_device_t* GetHALAdapter() const override {
+ return hal_adapter_;
+ }
+
+ // Initialize the interface. This loads the shared Bluetooth library and sets
+ // up the callbacks.
+ bool Initialize() {
+ // Load the Bluetooth shared library module.
+ const hw_module_t* module;
+ int status = hal_util_load_bt_library(&module);
+ if (status) {
+ LOG(ERROR) << "Failed to load Bluetooth library";
+ return false;
+ }
+
+ // Open the Bluetooth adapter.
+ hw_device_t* device;
+ status = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+ if (status) {
+ LOG(ERROR) << "Failed to open the Bluetooth module";
+ return false;
+ }
+
+ hal_adapter_ = reinterpret_cast<bluetooth_device_t*>(device);
+ hal_iface_ = hal_adapter_->get_bluetooth_interface();
+
+ // Initialize the Bluetooth interface. Set up the adapter (Bluetooth DM) API
+ // callbacks.
+ status = hal_iface_->init(&bt_callbacks);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize Bluetooth stack";
+ return false;
+ }
+
+ status = hal_iface_->set_os_callouts(&bt_os_callouts);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to set up Bluetooth OS callouts";
+ return false;
+ }
+
+ return true;
+ }
+
+ base::ObserverList<Observer>* observers() { return &observers_; }
+
+ private:
+ // List of observers that are interested in notifications from us. We're not
+ // using a base::ObserverListThreadSafe, which it posts observer events
+ // automatically on the origin threads, as we want to avoid that overhead and
+ // simply forward the events to the upper layer.
+ base::ObserverList<Observer> observers_;
+
+ // The HAL handle obtained from the shared library. We hold a weak reference
+ // to this since the actual data resides in the shared Bluetooth library.
+ const bt_interface_t* hal_iface_;
+
+ // The HAL handle that represents the underlying Bluetooth adapter. We hold a
+ // weak reference to this since the actual data resides in the shared
+ // Bluetooth library.
+ const bluetooth_device_t* hal_adapter_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothInterfaceImpl);
+};
+
+namespace {
+
+// Helper for obtaining the observer list from the global instance. This
+// function is NOT thread safe.
+base::ObserverList<BluetoothInterface::Observer>* GetObservers() {
+ CHECK(g_bluetooth_interface);
+ return static_cast<BluetoothInterfaceImpl*>(
+ g_bluetooth_interface)->observers();
+}
+
+} // namespace
+
+// static
+bool BluetoothInterface::Initialize() {
+ lock_guard<mutex> lock(g_instance_lock);
+ CHECK(!g_bluetooth_interface);
+
+ std::unique_ptr<BluetoothInterfaceImpl> impl(new BluetoothInterfaceImpl());
+ if (!impl->Initialize()) {
+ LOG(ERROR) << "Failed to initialize BluetoothInterface";
+ return false;
+ }
+
+ g_bluetooth_interface = impl.release();
+
+ return true;
+}
+
+// static
+void BluetoothInterface::CleanUp() {
+ lock_guard<mutex> lock(g_instance_lock);
+ CHECK(g_bluetooth_interface);
+
+ delete g_bluetooth_interface;
+ g_bluetooth_interface = nullptr;
+}
+
+// static
+BluetoothInterface* BluetoothInterface::Get() {
+ lock_guard<mutex> lock(g_instance_lock);
+ CHECK(g_bluetooth_interface);
+ return g_bluetooth_interface;
+}
+
+// static
+void BluetoothInterface::InitializeForTesting(
+ BluetoothInterface* test_instance) {
+ lock_guard<mutex> lock(g_instance_lock);
+ CHECK(test_instance);
+ CHECK(!g_bluetooth_interface);
+
+ g_bluetooth_interface = test_instance;
+}
+
+} // namespace hal
+} // namespace bluetooth
--- /dev/null
+//
+// 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
+
+#include <base/macros.h>
+#include <hardware/bluetooth.h>
+
+namespace bluetooth {
+namespace hal {
+
+// This class represents the HAL Bluetooth adapter interface, wrapping around
+// the underlying bt_interface_t structure, its methods, and callbacks. A single
+// instance of this class exists per application and it allows multiple classes
+// to interface with the global HAL interface by multiplexing callbacks among
+// registered clients.
+//
+// This is declared as an abstract interface so that a fake implementation can
+// be injected for testing the upper layer.
+//
+// TODO: (expose callback types directly but via redirection) methods for
+// initialize, clean up, and set for testing.
+class BluetoothInterface {
+ public:
+ // The standard Bluetooth adapter management callback interface. The HAL
+ // interface doesn't allow registering "user data" that carries context beyond
+ // the callback parameters, forcing implementations to deal with global
+ // variables. The Observer interface is to redirect these events to interested
+ // parties in an object-oriented manner.
+ //
+ // TODO(armansito): We should fix this in the HAL.
+ class Observer {
+ public:
+ virtual ~Observer() = default;
+
+ // All of the events below correspond to callbacks defined in
+ // "bt_callbacks_t" in the HAL API definitions.
+
+ virtual void AdapterStateChangedCallback(bt_state_t state) = 0;
+ virtual void AdapterPropertiesCallback(bt_status_t status,
+ int num_properties,
+ bt_property_t* properties) = 0;
+
+ // TODO(armansito): Complete the list of callbacks.
+ };
+
+ // Initialize and clean up the BluetoothInterface singleton. CleanUp must be
+ // called on the same thread that called Initialize.
+ static bool Initialize();
+ static void CleanUp();
+
+ // Initialize for testing. Use this to inject a test version of
+ // BlueoothInterface. To be used from unit tests only.
+ static void InitializeForTesting(BluetoothInterface* test_instance);
+
+ // Returns the BluetoothInterface singleton. If the interface has not been
+ // initialized, returns nullptr.
+ static BluetoothInterface* Get();
+
+ // Add or remove an observer that is interested in notifications from us.
+ virtual void AddObserver(Observer* observer) = 0;
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // The HAL module pointer that represents the standard Bluetooth adapter
+ // management interface. This is implemented in and provided by the shared
+ // Bluetooth library, so this isn't owned by us.
+ //
+ // Upper layers can make bt_interface_t API calls through this structure.
+ // However, DO NOT call the "init" function as this is called and managed by
+ // us. The behavior is undefined if "init" is called directly by upper layers.
+ virtual const bt_interface_t* GetHALInterface() const = 0;
+
+ // The HAL module pointer that represents the underlying Bluetooth adapter.
+ // This is implemented in and provided by the shared Bluetooth library, so
+ // this isn't owned by us.
+ virtual const bluetooth_device_t* GetHALAdapter() const = 0;
+
+ protected:
+ BluetoothInterface() = default;
+ virtual ~BluetoothInterface() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
--- /dev/null
+//
+// 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.
+//
+
+#include "service/hal/fake_bluetooth_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+FakeBluetoothInterface::Manager g_hal_manager;
+
+int FakeHALEnable() {
+ return g_hal_manager.enable_succeed ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+int FakeHALDisable() {
+ return g_hal_manager.disable_succeed ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+int FakeHALGetAdapterProperties() {
+ return BT_STATUS_SUCCESS;
+}
+
+int FakeHALSetAdapterProperty(const bt_property_t* /* property */) {
+ LOG(INFO) << __func__;
+ return (g_hal_manager.set_property_succeed ? BT_STATUS_SUCCESS :
+ BT_STATUS_FAIL);
+}
+
+bt_interface_t fake_bt_iface = {
+ sizeof(bt_interface_t),
+ nullptr, /* init */
+ FakeHALEnable,
+ FakeHALDisable,
+ nullptr, /* cleanup */
+ FakeHALGetAdapterProperties,
+ nullptr, /* get_adapter_property */
+ FakeHALSetAdapterProperty,
+ nullptr, /* get_remote_device_properties */
+ nullptr, /* get_remote_device_property */
+ nullptr, /* set_remote_device_property */
+ nullptr, /* get_remote_service_record */
+ nullptr, /* get_remote_services */
+ nullptr, /* start_discovery */
+ nullptr, /* cancel_discovery */
+ nullptr, /* create_bond */
+ nullptr, /* remove_bond */
+ nullptr, /* cancel_bond */
+ nullptr, /* get_connection_state */
+ nullptr, /* pin_reply */
+ nullptr, /* ssp_reply */
+ nullptr, /* get_profile_interface */
+ nullptr, /* dut_mode_configure */
+ nullptr, /* dut_more_send */
+ nullptr, /* le_test_mode */
+ nullptr, /* config_hci_snoop_log */
+ nullptr, /* set_os_callouts */
+ nullptr, /* read_energy_info */
+ nullptr, /* dump */
+};
+
+} // namespace
+
+// static
+FakeBluetoothInterface::Manager* FakeBluetoothInterface::GetManager() {
+ return &g_hal_manager;
+}
+
+FakeBluetoothInterface::Manager::Manager()
+ : enable_succeed(false),
+ disable_succeed(false),
+ set_property_succeed(false) {
+}
+
+void FakeBluetoothInterface::NotifyAdapterStateChanged(bt_state_t state) {
+ FOR_EACH_OBSERVER(Observer, observers_, AdapterStateChangedCallback(state));
+}
+
+void FakeBluetoothInterface::NotifyAdapterPropertiesChanged(
+ int num_properties,
+ bt_property_t* properties) {
+ FOR_EACH_OBSERVER(
+ Observer, observers_,
+ AdapterPropertiesCallback(BT_STATUS_SUCCESS, num_properties, properties));
+}
+
+void FakeBluetoothInterface::NotifyAdapterNamePropertyChanged(
+ const std::string& name) {
+ bt_bdname_t hal_name;
+ strncpy(reinterpret_cast<char*>(hal_name.name),
+ name.c_str(),
+ std::min(sizeof(hal_name)-1, name.length()));
+ reinterpret_cast<char*>(hal_name.name)[name.length()] = '\0';
+
+ bt_property_t property;
+ property.len = sizeof(hal_name);
+ property.val = &hal_name;
+ property.type = BT_PROPERTY_BDNAME;
+
+ NotifyAdapterPropertiesChanged(1, &property);
+}
+
+void FakeBluetoothInterface::NotifyAdapterAddressPropertyChanged(
+ const bt_bdaddr_t* address) {
+ bt_property_t property;
+ property.len = sizeof(bt_bdaddr_t);
+ property.val = (void*)address;
+ property.type = BT_PROPERTY_BDADDR;
+
+ NotifyAdapterPropertiesChanged(1, &property);
+}
+
+void FakeBluetoothInterface::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void FakeBluetoothInterface::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+const bt_interface_t* FakeBluetoothInterface::GetHALInterface() const {
+ return &fake_bt_iface;
+}
+
+const bluetooth_device_t* FakeBluetoothInterface::GetHALAdapter() const {
+ // TODO(armansito): Do something meaningful here to simulate test behavior.
+ return nullptr;
+}
+
+} // namespace hal
+} // namespace bluetooth
--- /dev/null
+//
+// 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.
+//
+
+#include "service/hal/bluetooth_interface.h"
+
+#include <base/macros.h>
+#include <base/observer_list.h>
+
+namespace bluetooth {
+namespace hal {
+
+class FakeBluetoothInterface : public BluetoothInterface {
+ public:
+ // A Fake HAL Bluetooth interface. This is kept as a global singleton as the
+ // Bluetooth HAL doesn't support anything otherwise.
+ struct Manager {
+ Manager();
+ ~Manager() = default;
+
+ // Values that should be returned from bt_interface_t methods.
+ bool enable_succeed;
+ bool disable_succeed;
+ bool set_property_succeed;
+ };
+
+ // Returns the global Manager.
+ static Manager* GetManager();
+
+ FakeBluetoothInterface() = default;
+ ~FakeBluetoothInterface() override = default;
+
+ // Notifies the observers that the adapter state changed to |state|.
+ void NotifyAdapterStateChanged(bt_state_t state);
+
+ // Triggers an adapter property change event.
+ void NotifyAdapterPropertiesChanged(int num_properties,
+ bt_property_t* properties);
+ void NotifyAdapterNamePropertyChanged(const std::string& name);
+ void NotifyAdapterAddressPropertyChanged(const bt_bdaddr_t* address);
+
+ // hal::BluetoothInterface overrides:
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+ const bt_interface_t* GetHALInterface() const override;
+ const bluetooth_device_t* GetHALAdapter() const override;
+
+ private:
+ base::ObserverList<Observer> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeBluetoothInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
--- /dev/null
+//
+// 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.
+//
+
+#include "service/ipc/binder/IBluetooth.h"
+
+#include <base/logging.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+
+using android::defaultServiceManager;
+using android::IBinder;
+using android::interface_cast;
+using android::IServiceManager;
+using android::Parcel;
+using android::sp;
+using android::String16;
+
+namespace ipc {
+namespace binder {
+
+// static
+const char IBluetooth::kBluetoothServiceName[] = "bluetooth-service";
+
+// static
+android::sp<IBluetooth> IBluetooth::getClientInterface() {
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (!sm.get()) {
+ LOG(ERROR) << "Failed to obtain a handle to the default Service Manager";
+ return nullptr;
+ }
+
+ sp<IBinder> binder = sm->getService(String16(kBluetoothServiceName));
+ if (!binder.get()) {
+ LOG(ERROR) << "Failed to obtain a handle to the Bluetooth service";
+ return nullptr;
+ }
+
+ sp<IBluetooth> bt_iface = interface_cast<IBluetooth>(binder);
+ if (!bt_iface.get()) {
+ LOG(ERROR) << "Obtained invalid IBinder handle";
+ return nullptr;
+ }
+
+ return bt_iface;
+}
+
+// BnBluetooth (server) implementation
+// ========================================================
+
+android::status_t BnBluetooth::onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags) {
+ VLOG(2) << "IBluetooth transaction: " << code;
+ if (!data.checkInterface(this))
+ return android::PERMISSION_DENIED;
+
+ switch (code) {
+ case IS_ENABLED_TRANSACTION: {
+ bool is_enabled = IsEnabled();
+ reply->writeInt32(is_enabled);
+ return android::NO_ERROR;
+ }
+ case GET_STATE_TRANSACTION: {
+ int state = GetState();
+ reply->writeInt32(state);
+ return android::NO_ERROR;
+ }
+ case ENABLE_TRANSACTION: {
+ bool result = Enable();
+ reply->writeInt32(result);
+ return android::NO_ERROR;
+ }
+ case DISABLE_TRANSACTION: {
+ bool result = Disable();
+ reply->writeInt32(result);
+ return android::NO_ERROR;
+ }
+ case GET_ADDRESS_TRANSACTION: {
+ std::string address = GetAddress();
+ reply->writeCString(address.c_str());
+ return android::NO_ERROR;
+ }
+ case GET_UUIDS_TRANSACTION:
+ // TODO(armansito): Figure out how to handle a Java "ParcelUuid" natively.
+ // (see http://b/23316698).
+ return android::INVALID_OPERATION;
+
+ case SET_NAME_TRANSACTION: {
+ std::string name(data.readCString());
+ bool result = SetName(name);
+ reply->writeInt32(result);
+ return android::NO_ERROR;
+ }
+ case GET_NAME_TRANSACTION: {
+ std::string name = GetName();
+ reply->writeCString(name.c_str());
+ return android::NO_ERROR;
+ }
+ case REGISTER_CALLBACK_TRANSACTION: {
+ sp<IBinder> callback = data.readStrongBinder();
+ RegisterCallback(interface_cast<IBluetoothCallback>(callback));
+ return android::NO_ERROR;
+ }
+ case UNREGISTER_CALLBACK_TRANSACTION: {
+ sp<IBinder> callback = data.readStrongBinder();
+ UnregisterCallback(interface_cast<IBluetoothCallback>(callback));
+ return android::NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// BpBluetooth (client) implementation
+// ========================================================
+
+BpBluetooth::BpBluetooth(const sp<IBinder>& impl)
+ : BpInterface<IBluetooth>(impl) {
+}
+
+bool BpBluetooth::IsEnabled() {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+ remote()->transact(IBluetooth::IS_ENABLED_TRANSACTION, data, &reply);
+
+ return reply.readInt32();
+}
+
+int BpBluetooth::GetState() {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+ remote()->transact(IBluetooth::GET_STATE_TRANSACTION, data, &reply);
+
+ return reply.readInt32();
+}
+
+bool BpBluetooth::Enable() {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+ remote()->transact(IBluetooth::ENABLE_TRANSACTION, data, &reply);
+
+ return reply.readInt32();
+}
+
+bool BpBluetooth::EnableNoAutoConnect() {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+ remote()->transact(IBluetooth::ENABLE_NO_AUTO_CONNECT_TRANSACTION,
+ data, &reply);
+
+ return reply.readInt32();
+}
+
+bool BpBluetooth::Disable() {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+ remote()->transact(IBluetooth::DISABLE_TRANSACTION, data, &reply);
+
+ return reply.readInt32();
+}
+
+std::string BpBluetooth::GetAddress() {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+ remote()->transact(IBluetooth::GET_ADDRESS_TRANSACTION, data, &reply);
+
+ return reply.readCString();
+}
+
+std::vector<bluetooth::UUID> BpBluetooth::GetUUIDs() {
+ // TODO(armansito): need to deserialize a parceled java.util.ParcelUUID[] to
+ // std::vector<bluetooth::UUID> here (see http://b/23316698).
+ return std::vector<bluetooth::UUID>();
+}
+
+bool BpBluetooth::SetName(const std::string& name) {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+ data.writeCString(name.c_str());
+ remote()->transact(IBluetooth::SET_NAME_TRANSACTION, data, &reply);
+
+ return reply.readInt32();
+}
+
+std::string BpBluetooth::GetName() {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+ remote()->transact(IBluetooth::GET_NAME_TRANSACTION, data, &reply);
+
+ return reply.readCString();
+}
+
+void BpBluetooth::RegisterCallback(const sp<IBluetoothCallback>& callback) {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(callback.get()));
+
+ remote()->transact(IBluetooth::REGISTER_CALLBACK_TRANSACTION, data, &reply);
+}
+
+void BpBluetooth::UnregisterCallback(const sp<IBluetoothCallback>& callback) {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(callback.get()));
+
+ remote()->transact(IBluetooth::UNREGISTER_CALLBACK_TRANSACTION, data, &reply);
+}
+
+IMPLEMENT_META_INTERFACE(Bluetooth, IBluetooth::kBluetoothServiceName);
+
+} // namespace binder
+} // namespace ipc
--- /dev/null
+//
+// 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
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+#include "service/ipc/binder/IBluetoothCallback.h"
+#include "service/uuid.h"
+
+namespace ipc {
+namespace binder {
+
+// This class defines the Binder IPC interface for accessing the Bluetooth
+// service. This class was written based on the corresponding AIDL file at
+// /frameworks/base/core/java/android/bluetooth/IBluetooth.aidl.
+//
+// NOTE: KEEP THIS FILE UP-TO-DATE with the corresponding AIDL, otherwise this
+// won't be compatible with the Android framework.
+class IBluetooth : public android::IInterface {
+ public:
+ DECLARE_META_INTERFACE(Bluetooth);
+
+ static const char kBluetoothServiceName[];
+
+ // Transaction codes for interface methods.
+ enum {
+ IS_ENABLED_TRANSACTION = android::IBinder::FIRST_CALL_TRANSACTION,
+ GET_STATE_TRANSACTION,
+ ENABLE_TRANSACTION,
+ ENABLE_NO_AUTO_CONNECT_TRANSACTION,
+ DISABLE_TRANSACTION,
+
+ GET_ADDRESS_TRANSACTION,
+ GET_UUIDS_TRANSACTION, // TODO(armansito): Support this
+ SET_NAME_TRANSACTION,
+ GET_NAME_TRANSACTION,
+
+ // TODO(armansito): Support the functions below.
+
+ GET_SCAN_MODE_TRANSACTION,
+ SET_SCAN_MODE_TRANSACTION,
+
+ GET_DISCOVERABLE_TIMEOUT_TRANSACTION,
+ SET_DISCOVERABLE_TIMEOUT_TRANSACTION,
+
+ START_DISCOVERY_TRANSACTION,
+ CANCEL_DISCOVERY_TRANSACTION,
+ IS_DISCOVERING_TRANSACTION,
+
+ GET_ADAPTER_CONNECTION_STATE_TRANSACTION,
+ GET_PROFILE_CONNECTION_STATE_TRANSACTION,
+
+ GET_BONDED_DEVICES_TRANSACTION,
+ CREATE_BOND_TRANSACTION,
+ CANCEL_BOND_PROCESS_TRANSACTION,
+ REMOVE_BOND_TRANSACTION,
+ GET_BOND_STATE_TRANSACTION,
+ GET_CONNECTION_STATE_TRANSACTION,
+
+ GET_REMOTE_NAME_TRANSACTION,
+ GET_REMOTE_TYPE_TRANSACTION,
+ GET_REMOTE_ALIAS_TRANSACTION,
+ SET_REMOTE_ALIAS_TRANSACTION,
+ GET_REMOTE_CLASS_TRANSACTION,
+ GET_REMOTE_UUIDS_TRANSACTION,
+ FETCH_REMOTE_UUIDS_TRANSACTION,
+ SDP_SEARCH_TRANSACTION,
+
+ SET_PIN_TRANSACTION,
+ SET_PASSKEY_TRANSACTION,
+ SET_PAIRING_CONFIRMATION_TRANSACTION,
+
+ GET_PHONEBOOK_ACCESS_PERMISSION_TRANSACTION,
+ SET_PHONEBOOK_ACCESS_PERMISSION_TRANSACTION,
+ GET_MESSAGE_ACCESS_PERMISSION_TRANSACTION,
+ SET_MESSAGE_ACCESS_PERMISSION_TRANSACTION,
+ GET_SIM_ACCESS_PERMISSION_TRANSACTION,
+ SET_SIM_ACCESS_PERMISSION_TRANSACTION,
+
+ SEND_CONNECTION_STATE_CHANGE_TRANSACTION,
+
+ REGISTER_CALLBACK_TRANSACTION,
+ UNREGISTER_CALLBACK_TRANSACTION,
+
+ CONNECT_SOCKET_TRANSACTION,
+ CREATE_SOCKET_CHANNEL_TRANSACTION,
+
+ CONFIG_HCI_SNOOP_LOG,
+ FACTORY_RESET_TRANSACTION,
+
+ IS_MULTI_ADVERTISEMENT_SUPPORTED_TRANSACTION,
+ IS_PERIPHERAL_MODE_SUPPORTED_TRANSACTION,
+ IS_OFFLOADED_FILTERING_SUPPORTED_TRANSACTION,
+ IS_OFFLOADED_SCAN_BATCHING_SUPPORTED_TRANSACTION,
+ IS_ACTIVITY_AND_ENERGY_REPORTING_SUPPORTED_TRANSACTION,
+ GET_ACTIVITY_ENERGY_INFO_FROM_CONTROLLER_TRANSACTION,
+ REPORT_ACTIVITY_INFO_TRANSACTION,
+
+ DUMP_TRANSACTION,
+ ON_LE_SERVICE_UP_TRANSACTION,
+ ON_BR_EDR_DOWN_TRANSACTION,
+ };
+
+ // Returns a handle to the IBluetooth Binder from the Android ServiceManager.
+ // Binder client code can use this to make calls to the service.
+ static android::sp<IBluetooth> getClientInterface();
+
+ // Methods declared in IBluetooth.aidl.
+
+ virtual bool IsEnabled() = 0;
+ virtual int GetState() = 0;
+ virtual bool Enable() = 0;
+ virtual bool EnableNoAutoConnect() = 0;
+ virtual bool Disable() = 0;
+
+ virtual std::string GetAddress() = 0;
+ virtual std::vector<bluetooth::UUID> GetUUIDs() = 0;
+ virtual bool SetName(const std::string& name) = 0;
+ virtual std::string GetName() = 0;
+
+ virtual void RegisterCallback(
+ const android::sp<IBluetoothCallback>& callback) = 0;
+ virtual void UnregisterCallback(
+ const android::sp<IBluetoothCallback>& callback) = 0;
+
+ // TODO(armansito): Complete the API definition.
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IBluetooth);
+};
+
+// TODO(armansito): Implement notification for when the process dies.
+
+// The Binder server interface to IBluetooth. A class that implements IBluetooth
+// must inherit from this class.
+class BnBluetooth : public android::BnInterface<IBluetooth> {
+ public:
+ BnBluetooth() = default;
+ virtual ~BnBluetooth() = default;
+
+ private:
+ virtual android::status_t onTransact(
+ uint32_t code,
+ const android::Parcel& data,
+ android::Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// The Binder client interface to IBluetooth.
+class BpBluetooth : public android::BpInterface<IBluetooth> {
+ public:
+ BpBluetooth(const android::sp<android::IBinder>& impl);
+ virtual ~BpBluetooth() = default;
+
+ // IBluetooth overrides:
+ bool IsEnabled() override;
+ int GetState() override;
+ bool Enable() override;
+ bool EnableNoAutoConnect() override;
+ bool Disable() override;
+ std::string GetAddress() override;
+ std::vector<bluetooth::UUID> GetUUIDs() override;
+ bool SetName(const std::string& name) override;
+ std::string GetName() override;
+ void RegisterCallback(
+ const android::sp<IBluetoothCallback>& callback) override;
+ void UnregisterCallback(
+ const android::sp<IBluetoothCallback>& callback) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BpBluetooth);
+};
+
+} // namespace binder
+} // namespace ipc
--- /dev/null
+//
+// 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.
+//
+
+#include "service/ipc/binder/IBluetoothCallback.h"
+
+#include <base/logging.h>
+#include <binder/Parcel.h>
+
+using android::IBinder;
+using android::Parcel;
+using android::sp;
+
+namespace ipc {
+namespace binder {
+
+// static
+const char IBluetoothCallback::kBluetoothCallbackServiceName[] =
+ "bluetooth-callback-service";
+
+// BnBluetoothCallback (server) implementation
+// ========================================================
+
+android::status_t BnBluetoothCallback::onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags) {
+ VLOG(2) << "IBluetoothCallback transaction: " << code;
+ if (!data.checkInterface(this))
+ return android::PERMISSION_DENIED;
+
+ switch (code) {
+ case ON_BLUETOOTH_STATE_CHANGE_TRANSACTION: {
+ int prev_state, new_state;
+ if (data.readInt32(&prev_state) != android::NO_ERROR ||
+ data.readInt32(&new_state) != android::NO_ERROR)
+ return android::NOT_ENOUGH_DATA;
+
+ OnBluetoothStateChange(
+ static_cast<bluetooth::AdapterState>(prev_state),
+ static_cast<bluetooth::AdapterState>(new_state));
+ return android::NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// BpBluetoothCallback (client) implementation
+// ========================================================
+
+BpBluetoothCallback::BpBluetoothCallback(const sp<IBinder>& impl)
+ : BpInterface<IBluetoothCallback>(impl) {
+}
+
+void BpBluetoothCallback::OnBluetoothStateChange(
+ bluetooth::AdapterState prev_state,
+ bluetooth::AdapterState new_state) {
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetoothCallback::getInterfaceDescriptor());
+ data.writeInt32(prev_state);
+ data.writeInt32(new_state);
+
+ remote()->transact(IBluetoothCallback::ON_BLUETOOTH_STATE_CHANGE_TRANSACTION,
+ data, &reply);
+}
+
+IMPLEMENT_META_INTERFACE(BluetoothCallback,
+ IBluetoothCallback::kBluetoothCallbackServiceName);
+
+} // namespace binder
+} // namespace ipc
--- /dev/null
+//
+// 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
+
+#include <base/macros.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+#include "service/adapter_state.h"
+
+namespace ipc {
+namespace binder {
+
+// This class defines the Binder IPC interface for receiving adapter state
+// updates from the Bluetooth service. This class was written based on the
+// corresponding AIDL file at
+// /frameworks/base/core/java/android/bluetooth/IBluetoothCallback.aidl.
+//
+// NOTE: KEEP THIS FILE UP-TO-DATE with the corresponding AIDL, otherwise this
+// won't be compatible with the Android framework.
+class IBluetoothCallback : public android::IInterface {
+ public:
+ DECLARE_META_INTERFACE(BluetoothCallback);
+
+ static const char kBluetoothCallbackServiceName[];
+
+ // Transaction codes for interface methods.
+ enum {
+ ON_BLUETOOTH_STATE_CHANGE_TRANSACTION =
+ android::IBinder::FIRST_CALL_TRANSACTION,
+ };
+
+ virtual void OnBluetoothStateChange(
+ bluetooth::AdapterState prev_state,
+ bluetooth::AdapterState new_state) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IBluetoothCallback);
+};
+
+// TODO(armansito): Implement notification for when the process dies.
+
+// The Binder server interface to IBluetoothCallback. A class that implements
+// IBluetoothCallback must inherit from this class.
+class BnBluetoothCallback : public android::BnInterface<IBluetoothCallback> {
+ public:
+ BnBluetoothCallback() = default;
+ virtual ~BnBluetoothCallback() = default;
+
+ private:
+ virtual android::status_t onTransact(
+ uint32_t code,
+ const android::Parcel& data,
+ android::Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// The Binder client interface to IBluetoothCallback.
+class BpBluetoothCallback : public android::BpInterface<IBluetoothCallback> {
+ public:
+ BpBluetoothCallback(const android::sp<android::IBinder>& impl);
+ virtual ~BpBluetoothCallback() = default;
+
+ // IBluetoothCallback override:
+ void OnBluetoothStateChange(bluetooth::AdapterState prev_state,
+ bluetooth::AdapterState new_state) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BpBluetoothCallback);
+};
+
+} // namespace binder
+} // namespace ipc
--- /dev/null
+//
+// 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.
+//
+
+#include "service/ipc/binder/bluetooth_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+namespace ipc {
+namespace binder {
+
+BluetoothBinderServer::BluetoothBinderServer(bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+ adapter_->AddObserver(this);
+}
+
+BluetoothBinderServer::~BluetoothBinderServer() {
+ adapter_->RemoveObserver(this);
+}
+
+// binder::BnBluetooth overrides:
+bool BluetoothBinderServer::IsEnabled() {
+ VLOG(2) << __func__;
+ return adapter_->IsEnabled();
+}
+
+int BluetoothBinderServer::GetState() {
+ VLOG(2) << __func__;
+ return adapter_->GetState();
+}
+
+bool BluetoothBinderServer::Enable() {
+ VLOG(2) << __func__;
+ return adapter_->Enable();
+}
+
+bool BluetoothBinderServer::EnableNoAutoConnect() {
+ VLOG(2) << __func__;
+ // TODO(armansito): Implement.
+ return false;
+}
+
+bool BluetoothBinderServer::Disable() {
+ VLOG(2) << __func__;
+ return adapter_->Disable();
+}
+
+std::string BluetoothBinderServer::GetAddress() {
+ return adapter_->GetAddress();
+}
+
+std::vector<bluetooth::UUID> BluetoothBinderServer::GetUUIDs() {
+ // TODO(armansito): Implement.
+ return std::vector<bluetooth::UUID>();
+}
+
+bool BluetoothBinderServer::SetName(const std::string& name) {
+ return adapter_->SetName(name);
+}
+
+std::string BluetoothBinderServer::GetName() {
+ return adapter_->GetName();
+}
+
+void BluetoothBinderServer::RegisterCallback(
+ const android::sp<IBluetoothCallback>& callback) {
+ VLOG(2) << __func__;
+ if (!callback.get() ) {
+ LOG(ERROR) << "RegisterCallback called with NULL binder. Ignoring.";
+ return;
+ }
+ callbacks_.Register(callback);
+}
+
+void BluetoothBinderServer::UnregisterCallback(
+ const android::sp<IBluetoothCallback>& callback) {
+ VLOG(2) << __func__;
+ if (!callback.get() ) {
+ LOG(ERROR) << "UnregisterCallback called with NULL binder. Ignoring.";
+ return;
+ }
+ callbacks_.Unregister(callback);
+}
+
+void BluetoothBinderServer::OnAdapterStateChanged(
+ bluetooth::Adapter* adapter,
+ bluetooth::AdapterState prev_state,
+ bluetooth::AdapterState new_state) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received adapter state update - prev: " << prev_state
+ << " new: " << new_state;
+ callbacks_.ForEach([prev_state, new_state](IBluetoothCallback* callback) {
+ callback->OnBluetoothStateChange(prev_state, new_state);
+ });
+}
+
+} // namespace binder
+} // namespace ipc
--- /dev/null
+//
+// 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
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+#include "service/adapter.h"
+#include "service/ipc/binder/IBluetooth.h"
+#include "service/ipc/binder/IBluetoothCallback.h"
+#include "service/ipc/binder/remote_callback_list.h"
+#include "service/uuid.h"
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetooth Binder interface.
+class BluetoothBinderServer : public BnBluetooth,
+ public bluetooth::Adapter::Observer {
+ public:
+ explicit BluetoothBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothBinderServer() override;
+
+ // IBluetooth overrides:
+ bool IsEnabled() override;
+ int GetState() override;
+ bool Enable() override;
+ bool EnableNoAutoConnect() override;
+ bool Disable() override;
+
+ std::string GetAddress() override;
+ std::vector<bluetooth::UUID> GetUUIDs() override;
+ bool SetName(const std::string& name) override;
+ std::string GetName() override;
+
+ void RegisterCallback(
+ const android::sp<IBluetoothCallback>& callback) override;
+ void UnregisterCallback(
+ const android::sp<IBluetoothCallback>& callback) override;
+
+ // bluetooth::Adapter::Observer overrides:
+ void OnAdapterStateChanged(bluetooth::Adapter* adapter,
+ bluetooth::AdapterState prev_state,
+ bluetooth::AdapterState new_state) override;
+
+ private:
+ // Weak handle on the Adapter.
+ bluetooth::Adapter* adapter_;
+ RemoteCallbackList<IBluetoothCallback> callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
--- /dev/null
+//
+// 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.
+//
+
+#include "service/ipc/binder/ipc_handler_binder.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "service/ipc/binder/bluetooth_binder_server.h"
+
+using android::defaultServiceManager;
+using android::sp;
+using android::status_t;
+using android::String16;
+
+namespace ipc {
+
+IPCHandlerBinder::IPCHandlerBinder(
+ bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate)
+ : IPCHandler(adapter, delegate) {
+}
+
+IPCHandlerBinder::~IPCHandlerBinder() {
+}
+
+bool IPCHandlerBinder::Run() {
+ CHECK(adapter());
+
+ // Register the IBluetooth service with the Android ServiceManager.
+ android::sp<binder::BluetoothBinderServer> bt_server =
+ new binder::BluetoothBinderServer(adapter());
+ status_t status = defaultServiceManager()->addService(
+ String16(binder::IBluetooth::kBluetoothServiceName),
+ bt_server);
+ if (status != android::NO_ERROR) {
+ LOG(ERROR) << "Failed to register Bluetooth service with ServiceManager";
+ return false;
+ }
+
+ // Notify the delegate. We do this in the message loop to avoid reentrancy.
+ if (delegate()) {
+ base::MessageLoop::current()->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&IPCHandlerBinder::NotifyStarted, this));
+ }
+
+ android::ProcessState::self()->startThreadPool();
+
+ return true;
+}
+
+void IPCHandlerBinder::Stop() {
+ // TODO(armansito): There are several methods in android::IPCThreadState that
+ // are related to shutting down the threadpool, however I haven't been able to
+ // make them shut things down cleanly. Figure out the right way to stop the
+ // Binder IPC here.
+}
+
+void IPCHandlerBinder::NotifyStarted() {
+ if (delegate())
+ delegate()->OnIPCHandlerStarted(IPCManager::TYPE_BINDER);
+}
+
+} // namespace ipc
--- /dev/null
+//
+// 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
+
+#include <base/macros.h>
+
+#include "service/ipc/ipc_handler.h"
+#include "service/ipc/ipc_manager.h"
+
+namespace ipc {
+
+// Implements a Binder based IPCHandler.
+class IPCHandlerBinder : public IPCHandler {
+ public:
+ IPCHandlerBinder(bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate);
+ ~IPCHandlerBinder() override;
+
+ // IPCHandler overrides:
+ bool Run() override;
+ void Stop() override;
+
+ private:
+ IPCHandlerBinder() = default;
+
+ // Notify the delegate that IPC has started.
+ void NotifyStarted();
+
+ DISALLOW_COPY_AND_ASSIGN(IPCHandlerBinder);
+};
+
+} // namespace ipc
--- /dev/null
+//
+// 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
+
+#include <functional>
+#include <map>
+#include <mutex>
+
+#include <base/logging.h>
+#include <base/macros.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+namespace ipc {
+namespace binder {
+
+// Takes care of the grunt work of maintaining a list of remote interfaces,
+// typically for the use of performing registered callbacks from a remote
+// service. This is a native equivalent of the the android.os.RemoteCallbackList
+// Java class. The type "T" must inherit from android::IInterface.
+//
+// TODO(armansito): We need to unit test this class. Right now it's defined as a
+// simple template interface over the native libbinder types directly and we
+// can't compile libbinder for host unless the Binder kernel module is enabled
+// on the system. Figure out whether to:
+// 1) write the Binder test-code in a new target-only executable;
+// 2) conditionally compile into the host-native test suite if the Binder
+// module is built;
+// 3) provide a test-only static library that re-defines the libbinder
+// classes as mocks.
+// (See http://b/23386387)
+//
+// TODO(armansito): We should make this class non-final and the template
+// interface abstract, so that code that depends on this can be unit tested
+// against a mock version of this class.
+//
+// TODO(armansito): Consider submitting this class to frameworks/native/binder.
+template<typename T>
+class RemoteCallbackList final {
+ public:
+ RemoteCallbackList() = default;
+ ~RemoteCallbackList();
+
+ // Register and unregister a callback interface. Registering will
+ // automatically start tracking for death notifications in case the remote
+ // process hosting the Binder dies. In such a case, the Binder is
+ // automatically removed from the list.
+ bool Register(const android::sp<T>& callback);
+ bool Unregister(const android::sp<T>& callback);
+
+ // Calls the given function on each of the contained callbacks. The internal
+ // mutex is locked for the duration of the iteration.
+ void ForEach(const std::function<void(T*)>& callback);
+
+ private:
+ class CallbackDeathRecipient : public android::IBinder::DeathRecipient {
+ public:
+ explicit CallbackDeathRecipient(const android::sp<T>& callback,
+ RemoteCallbackList* owner);
+
+ android::sp<T> get_callback() const { return callback_; }
+
+ // android::DeathRecipient override:
+ void binderDied(const android::wp<android::IBinder>& who) override;
+
+ private:
+ android::sp<T> callback_;
+ RemoteCallbackList<T>* owner_; // weak
+ };
+
+ // Typedef for internal map container. This keeps track of a given Binder and
+ // a death receiver associated with it.
+ using CallbackMap = std::map<android::sp<android::IBinder>,
+ android::sp<CallbackDeathRecipient>>;
+
+ bool UnregisterInternal(typename CallbackMap::iterator iter);
+
+ std::mutex map_lock_;
+ CallbackMap callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteCallbackList);
+};
+
+// Template Implementation details below
+// ========================================================
+
+using android::IBinder;
+using android::IInterface;
+using android::sp;
+using android::wp;
+
+template<typename T>
+RemoteCallbackList<T>::~RemoteCallbackList() {
+ std::lock_guard<std::mutex> lock(map_lock_);
+ for (auto iter = callbacks_.begin(); iter != callbacks_.end(); ++iter)
+ UnregisterInternal(iter);
+}
+
+template<typename T>
+bool RemoteCallbackList<T>::Register(const sp<T>& callback) {
+ std::lock_guard<std::mutex> lock(map_lock_);
+
+ sp<IBinder> binder = IInterface::asBinder(callback.get());
+ if (callbacks_.find(binder) != callbacks_.end()) {
+ VLOG(1) << "Callback list already contains given callback";
+ return false;
+ }
+
+ sp<CallbackDeathRecipient> dr(new CallbackDeathRecipient(callback, this));
+
+ if (binder->linkToDeath(dr) != android::NO_ERROR) {
+ LOG(ERROR) << "Failed to link death recipient to binder";
+ return false;
+ }
+
+ callbacks_[binder] = dr;
+
+ VLOG(1) << "Callback successfully registered";
+
+ return true;
+}
+
+template<typename T>
+bool RemoteCallbackList<T>::Unregister(const sp<T>& callback) {
+ std::lock_guard<std::mutex> lock(map_lock_);
+
+ sp<IBinder> binder = IInterface::asBinder(callback.get());
+ auto iter = callbacks_.find(binder);
+ if (iter == callbacks_.end()) {
+ VLOG(1) << "Given callback not registered";
+ return false;
+ }
+
+ return UnregisterInternal(iter);
+}
+
+template<typename T>
+void RemoteCallbackList<T>::ForEach(const std::function<void(T*)>& callback) {
+ std::lock_guard<std::mutex> lock(map_lock_);
+ for (const auto& iter : callbacks_)
+ callback(iter.second->get_callback().get());
+}
+
+template<typename T>
+bool RemoteCallbackList<T>::UnregisterInternal(
+ typename CallbackMap::iterator iter) {
+ sp<CallbackDeathRecipient> dr = iter->second;
+ callbacks_.erase(iter);
+
+ if (IInterface::asBinder(dr->get_callback().get())->unlinkToDeath(dr) !=
+ android::NO_ERROR) {
+ LOG(ERROR) << "Failed to unlink death recipient from binder";
+ return false;
+ }
+
+ VLOG(1) << "Callback successfully unregistered";
+
+ return true;
+}
+
+template<typename T>
+RemoteCallbackList<T>::CallbackDeathRecipient::CallbackDeathRecipient(
+ const sp<T>& callback,
+ RemoteCallbackList<T>* owner)
+ : callback_(callback),
+ owner_(owner) {
+ CHECK(callback_.get());
+ CHECK(owner_);
+}
+
+template<typename T>
+void RemoteCallbackList<T>::CallbackDeathRecipient::binderDied(
+ const wp<IBinder>& who) {
+ VLOG(1) << "Received binderDied";
+
+ sp<IBinder> binder = IInterface::asBinder(callback_.get());
+ CHECK(who.unsafe_get() == binder.get());
+
+ // Remove the callback but no need to call unlinkToDeath.
+ std::lock_guard<std::mutex> lock(owner_->map_lock_);
+ auto iter = owner_->callbacks_.find(binder);
+ CHECK(iter != owner_->callbacks_.end());
+ owner_->callbacks_.erase(iter);
+
+ VLOG(1) << "Callback from dead process unregistered";
+}
+
+} // namespace binder
+} // namespace ipc
--- /dev/null
+//
+// 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.
+//
+
+#include "service/ipc/ipc_handler.h"
+
+#include <base/logging.h>
+
+namespace ipc {
+
+IPCHandler::IPCHandler(bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate)
+ : adapter_(adapter),
+ delegate_(delegate) {
+ CHECK(adapter_);
+}
+
+IPCHandler::~IPCHandler() {
+}
+
+} // namespace ipc
--- /dev/null
+//
+// 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
+
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+
+#include "service/ipc/ipc_manager.h"
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+
+// IPCHandler is an interface that classes implementing different IPC mechanisms
+// must conform to.
+class IPCHandler : public base::RefCountedThreadSafe<IPCHandler> {
+ public:
+ IPCHandler(bluetooth::Adapter* adapter, IPCManager::Delegate* delegate);
+ virtual ~IPCHandler();
+
+ // Initializes and runs the IPC mechanism. Returns true on success, false
+ // otherwise.
+ virtual bool Run() = 0;
+
+ // Stops the IPC mechanism.
+ virtual void Stop() = 0;
+
+ protected:
+ // Getters for private members to allow subclasses to access them in read-only
+ // fashion.
+ bluetooth::Adapter* adapter() const { return adapter_; }
+ IPCManager::Delegate* delegate() const { return delegate_; }
+
+ private:
+ IPCHandler() = default;
+
+ // Weak reference to the global Adapter instance.
+ bluetooth::Adapter* adapter_;
+
+ // The delegate that is interested in notifications from us.
+ IPCManager::Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCHandler);
+};
+
+} // namespace ipc
--- /dev/null
+//
+// 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.
+//
+
+#include "service/ipc/ipc_handler_unix.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <base/bind.h>
+
+#include "osi/include/socket_utils/sockets.h"
+#include "service/daemon.h"
+#include "service/ipc/unix_ipc_host.h"
+#include "service/settings.h"
+
+namespace ipc {
+
+IPCHandlerUnix::IPCHandlerUnix(bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate)
+ : IPCHandler(adapter, delegate),
+ running_(false),
+ thread_("IPCHandlerUnix"),
+ keep_running_(true) {
+}
+
+IPCHandlerUnix::~IPCHandlerUnix() {
+ // This will only be set if the Settings::create_ipc_socket_path() was
+ // originally provided.
+ if (!socket_path_.empty())
+ unlink(socket_path_.value().c_str());
+}
+
+bool IPCHandlerUnix::Run() {
+ CHECK(!running_);
+
+ const std::string& android_suffix =
+ bluetooth::Daemon::Get()->GetSettings()->android_ipc_socket_suffix();
+ const base::FilePath& path =
+ bluetooth::Daemon::Get()->GetSettings()->create_ipc_socket_path();
+
+ // Both flags cannot be set at the same time.
+ CHECK(android_suffix.empty() || path.empty());
+ if (android_suffix.empty() && path.empty()) {
+ LOG(ERROR) << "No domain socket path provided";
+ return false;
+ }
+
+ CHECK(base::MessageLoop::current()); // An origin event loop is required.
+ origin_task_runner_ = base::MessageLoop::current()->task_runner();
+
+ if (!android_suffix.empty()) {
+ int server_fd = osi_android_get_control_socket(android_suffix.c_str());
+ if (server_fd == -1) {
+ LOG(ERROR) << "Unable to get Android socket from: " << android_suffix;
+ return false;
+ }
+ LOG(INFO) << "Binding to Android server socket:" << android_suffix;
+ socket_.reset(server_fd);
+ } else {
+ LOG(INFO) << "Creating a Unix domain socket:" << path.value();
+
+ // 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.
+ unlink(path.value().c_str());
+
+ base::ScopedFD server_socket(socket(PF_UNIX, SOCK_SEQPACKET, 0));
+ if (!server_socket.is_valid()) {
+ LOG(ERROR) << "Failed to open domain socket for IPC";
+ return false;
+ }
+
+ struct sockaddr_un address;
+ memset(&address, 0, sizeof(address));
+ address.sun_family = AF_UNIX;
+ strncpy(address.sun_path, path.value().c_str(),
+ sizeof(address.sun_path) - 1);
+ if (bind(server_socket.get(), (struct sockaddr*)&address, sizeof(address)) <
+ 0) {
+ LOG(ERROR) << "Failed to bind IPC socket to address: " << strerror(errno);
+ return false;
+ }
+
+ socket_.swap(server_socket);
+ socket_path_ = path;
+ }
+
+ CHECK(socket_.is_valid());
+
+ running_ = true; // Set this here before launching the thread.
+
+ // Start an IO thread and post the listening task.
+ base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
+ if (!thread_.StartWithOptions(options)) {
+ LOG(ERROR) << "Failed to start IPCHandlerUnix thread";
+ running_ = false;
+ return false;
+ }
+
+ thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&IPCHandlerUnix::StartListeningOnThread, this));
+
+ return true;
+}
+
+void IPCHandlerUnix::Stop() {
+ keep_running_ = false;
+
+ // At this moment the listening thread might be blocking on the accept
+ // syscall. Shutdown and close the server socket before joining the thread to
+ // interrupt accept so that the main thread doesn't keep blocking.
+ shutdown(socket_.get(), SHUT_RDWR);
+ socket_.reset();
+
+ // Join and clean up the thread.
+ thread_.Stop();
+
+ // Thread exited. Notify the delegate. Post this on the event loop so that the
+ // callback isn't reentrant.
+ NotifyStoppedOnOriginThread();
+}
+
+void IPCHandlerUnix::StartListeningOnThread() {
+ CHECK(socket_.is_valid());
+ CHECK(adapter());
+ CHECK(running_);
+
+ LOG(INFO) << "Listening to incoming connections";
+
+ int status = listen(socket_.get(), SOMAXCONN);
+ if (status < 0) {
+ LOG(ERROR) << "Failed to listen on domain socket: " << strerror(errno);
+ origin_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&IPCHandlerUnix::ShutDownOnOriginThread, this));
+ return;
+ }
+
+ NotifyStartedOnOriginThread();
+
+ // TODO(armansito): The code below can cause the daemon to run indefinitely if
+ // the thread is joined while it's in the middle of the EventLoop() call. The
+ // EventLoop() won't exit until a client terminates the connection, however
+ // this can be fixed by using the |thread_|'s MessageLoopForIO instead (since
+ // it gets stopped along with the thread).
+ // TODO(icoolidge): accept simultaneous clients
+ while (keep_running_.load()) {
+ int client_socket = accept4(socket_.get(), nullptr, nullptr, SOCK_NONBLOCK);
+ if (client_socket < 0) {
+ LOG(ERROR) << "Failed to accept client connection: " << strerror(errno);
+ continue;
+ }
+
+ LOG(INFO) << "Established client connection: fd=" << client_socket;
+
+ UnixIPCHost ipc_host(client_socket, adapter());
+
+ // TODO(armansito): Use |thread_|'s MessageLoopForIO instead of using a
+ // custom event loop to poll from the socket.
+ ipc_host.EventLoop();
+ }
+}
+
+void IPCHandlerUnix::ShutDownOnOriginThread() {
+ LOG(INFO) << "Shutting down IPCHandlerUnix thread";
+ thread_.Stop();
+ running_ = false;
+
+ NotifyStoppedOnCurrentThread();
+}
+
+void IPCHandlerUnix::NotifyStartedOnOriginThread() {
+ if (!delegate())
+ return;
+
+ origin_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&IPCHandlerUnix::NotifyStartedOnCurrentThread, this));
+}
+
+void IPCHandlerUnix::NotifyStartedOnCurrentThread() {
+ if (delegate())
+ delegate()->OnIPCHandlerStarted(IPCManager::TYPE_UNIX);
+}
+
+void IPCHandlerUnix::NotifyStoppedOnOriginThread() {
+ if (!delegate())
+ return;
+
+ origin_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&IPCHandlerUnix::NotifyStoppedOnCurrentThread, this));
+}
+
+void IPCHandlerUnix::NotifyStoppedOnCurrentThread() {
+ if (delegate())
+ delegate()->OnIPCHandlerStopped(IPCManager::TYPE_UNIX);
+}
+
+} // namespace ipc
--- /dev/null
+//
+// 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
+
+#include <atomic>
+
+#include <base/files/file_path.h>
+#include <base/files/scoped_file.h>
+#include <base/macros.h>
+#include <base/threading/thread.h>
+
+#include "service/ipc/ipc_handler.h"
+#include "service/ipc/ipc_manager.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace ipc {
+
+// Implements a UNIX domain-socket based IPCHandler
+class IPCHandlerUnix : public IPCHandler {
+ public:
+ IPCHandlerUnix(bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate);
+ ~IPCHandlerUnix() override;
+
+ // IPCHandler overrides:
+ bool Run() override;
+ void Stop() override;
+
+ private:
+ IPCHandlerUnix() = default;
+
+ // Starts listening for incoming connections. Posted on |thread_| by Run().
+ void StartListeningOnThread();
+
+ // Stops the IPC thread. This helper is needed since base::Thread requires
+ // threads to be stopped on the thread that started them.
+ void ShutDownOnOriginThread();
+
+ // Notifies the delegate that we started or stoppedlistening for incoming
+ // connections.
+ void NotifyStartedOnOriginThread();
+ void NotifyStartedOnCurrentThread();
+ void NotifyStoppedOnOriginThread();
+ void NotifyStoppedOnCurrentThread();
+
+ // True, if the IPC mechanism is running.
+ bool running_;
+
+ // The server socket on which we listen to incoming connections.
+ base::ScopedFD socket_;
+
+ // The file path to |socket_|. This is only set if we create and manage the
+ // life time of the socket.
+ base::FilePath socket_path_;
+
+ // We use a dedicated thread for listening to incoming connections and
+ // polling from the socket to avoid blocking the main thread.
+ base::Thread thread_;
+
+ // Whether or not the listening thread should continue to run.
+ std::atomic<bool> keep_running_;
+
+ // The origin thread's task runner.
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCHandlerUnix);
+};
+
+} // namespace ipc
--- /dev/null
+//
+// 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.
+//
+
+#include "service/ipc/ipc_manager.h"
+
+#include "service/ipc/binder/ipc_handler_binder.h"
+#include "service/ipc/ipc_handler_unix.h"
+
+namespace ipc {
+
+IPCManager::IPCManager(bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+}
+
+IPCManager::~IPCManager() {
+ // Don't rely on the handlers getting destroyed since another thread might be
+ // holding a reference to them. Instead, explicitly stop them here.
+ if (BinderStarted())
+ binder_handler_->Stop();
+ if (UnixStarted())
+ unix_handler_->Stop();
+}
+
+bool IPCManager::Start(Type type, Delegate* delegate) {
+ switch (type) {
+ case TYPE_UNIX:
+ if (UnixStarted()) {
+ LOG(ERROR) << "IPCManagerUnix already started.";
+ return false;
+ }
+
+ unix_handler_ = new IPCHandlerUnix(adapter_, delegate);
+ if (!unix_handler_->Run()) {
+ unix_handler_ = nullptr;
+ return false;
+ }
+ return true;
+
+ case TYPE_BINDER:
+ if (BinderStarted()) {
+ LOG(ERROR) << "IPCManagerBinder already started.";
+ return false;
+ }
+
+ binder_handler_ = new IPCHandlerBinder(adapter_, delegate);
+ if (!binder_handler_->Run()) {
+ binder_handler_ = nullptr;
+ return false;
+ }
+ return true;
+
+ default:
+ LOG(ERROR) << "Unsupported IPC type given: " << type;
+ }
+
+ return false;
+}
+
+bool IPCManager::BinderStarted() const {
+ return binder_handler_.get();
+}
+
+bool IPCManager::UnixStarted() const {
+ return unix_handler_.get();
+}
+
+} // namespace ipc
--- /dev/null
+//
+// 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
+
+#include <memory>
+
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+
+class IPCHandler;
+
+// IPCManager is a class for initializing and running supported IPC mechanisms.
+// It manages the life-time of different IPC flavors that are available on the
+// system. There are two flavors: a plain UNIX domain socket based system and
+// one based on the Binder-based android.bluetooth framework.
+class IPCManager {
+ public:
+ // Possible IPC types.
+ enum Type {
+ TYPE_UNIX, // IPC based on a UNIX domain socket
+ TYPE_BINDER // IPC based on the Binder
+ };
+
+ // Interface for observing events from an IPC mechanism. These methods will be
+ // called on the thread that started the particular IPC type.
+ class Delegate {
+ public:
+ Delegate() = default;
+ virtual ~Delegate() = default;
+
+ // Called when an IPC mechanism has successfully started and is ready for
+ // client connections.
+ virtual void OnIPCHandlerStarted(Type type) = 0;
+
+ // Called when an IPC mechanism has stopped. This may happen due to an error
+ // in initialization or due to a regular shut down routine.
+ virtual void OnIPCHandlerStopped(Type type) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+ };
+
+ explicit IPCManager(bluetooth::Adapter* adapter);
+ ~IPCManager();
+
+ // Initialize the underlying IPC handler based on |type|, if that type has not
+ // yet been initialized and returns true on success. Returns false if that
+ // type has already been initialized or an error occurs.
+ //
+ // If TYPE_UNIX is given, the file path to use for the domain socket will be
+ // obtained from the global Settings object. Hence, the Settings object must
+ // have been initialized before calling this method.
+ //
+ // |delegate| must out-live the IPCManager and the underlying handler. Users
+ // can guarantee proper clean up by deallocating |delegate| when or after
+ // Delegate::OnIPCHandlerStopped is called. It is safe to destroy |delegate|
+ // after destroying the IPCManager instance, as the destructor will join and
+ // clean up all underlying threads.
+ bool Start(Type type, Delegate* delegate);
+
+ // Returns true if an IPC type has been initialized.
+ bool BinderStarted() const;
+ bool UnixStarted() const;
+
+ private:
+ IPCManager() = default;
+
+ // Pointers to the different IPC handler classes. These are initialized and
+ // owned by us.
+ scoped_refptr<IPCHandler> binder_handler_;
+ scoped_refptr<IPCHandler> unix_handler_;
+
+ // The Bluetooth adapter instance. This is owned by Daemon so we keep a raw
+ // pointer to it.
+ bluetooth::Adapter* adapter_;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCManager);
+};
+
+} // namespace ipc
--- /dev/null
+//
+// 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 "bt_bluetooth_host"
+
+#include "service/ipc/unix_ipc_host.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include <base/base64.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
+
+#include "osi/include/log.h"
+#include "service/adapter.h"
+#include "service/gatt_server.h"
+#include "service/uuid.h"
+
+using bluetooth::Adapter;
+using bluetooth::UUID;
+
+using namespace bluetooth::gatt;
+
+namespace {
+
+// IPC API is according to:
+// https://docs.google.com/document/d/1eRnku-jAyVU1wGJsLT2CzWi0-8bs2g49s1b3FR_GApM
+const char kSetAdapterNameCommand[] = "set-device-name";
+const char kCreateServiceCommand[] = "create-service";
+const char kDestroyServiceCommand[] = "destroy-service";
+const char kAddCharacteristicCommand[] = "add-characteristic";
+const char kSetCharacteristicValueCommand[] = "set-characteristic-value";
+const char kSetAdvertisementCommand[] = "set-advertisement";
+const char kSetScanResponseCommand[] = "set-scan-response";
+const char kStartServiceCommand[] = "start-service";
+const char kStopServiceCommand[] = "stop-service";
+const char kWriteCharacteristicCommand[] = "write-characteristic";
+
+// Useful values for indexing UnixIPCHost::pfds_
+// Not super general considering that we should be able to support
+// many GATT FDs owned by one UnixIPCHost.
+enum {
+ kFdIpc = 0,
+ kFdGatt = 1,
+ kPossibleFds = 2,
+};
+
+bool TokenBool(const std::string& text) {
+ return text == "true";
+}
+
+} // namespace
+
+namespace ipc {
+
+UnixIPCHost::UnixIPCHost(int sockfd, Adapter* adapter)
+ : adapter_(adapter), pfds_(1, {sockfd, POLLIN, 0}) {}
+
+UnixIPCHost::~UnixIPCHost() {
+ close(pfds_[0].fd);
+}
+
+bool UnixIPCHost::EventLoop() {
+ while (true) {
+ int status =
+ TEMP_FAILURE_RETRY(ppoll(pfds_.data(), pfds_.size(), nullptr, nullptr));
+ if (status < 1) {
+ LOG_ERROR(LOG_TAG, "ppoll error");
+ return false;
+ }
+
+ if (pfds_[kFdIpc].revents && !OnMessage()) {
+ return false;
+ }
+
+ if (pfds_.size() == kPossibleFds &&
+ pfds_[kFdGatt].revents &&
+ !OnGattWrite()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool UnixIPCHost::OnSetAdapterName(const std::string& name) {
+ std::string decoded_data;
+ base::Base64Decode(name, &decoded_data);
+ return adapter_->SetName(decoded_data);
+}
+
+bool UnixIPCHost::OnCreateService(const std::string& service_uuid) {
+ gatt_servers_[service_uuid] = std::unique_ptr<Server>(new Server);
+
+ int gattfd;
+ bool status = gatt_servers_[service_uuid]->Initialize(
+ UUID(service_uuid), &gattfd);
+ if (!status) {
+ LOG_ERROR(LOG_TAG, "Failed to initialize bluetooth");
+ return false;
+ }
+ pfds_.resize(kPossibleFds);
+ pfds_[kFdGatt] = {gattfd, POLLIN, 0};
+ return true;
+}
+
+bool UnixIPCHost::OnDestroyService(const std::string& service_uuid) {
+ gatt_servers_.erase(service_uuid);
+ close(pfds_[1].fd);
+ pfds_.resize(1);
+ return true;
+}
+
+bool UnixIPCHost::OnAddCharacteristic(const std::string& service_uuid,
+ const std::string& characteristic_uuid,
+ const std::string& control_uuid,
+ const std::string& options) {
+ std::vector<std::string> option_tokens;
+ base::SplitString(options, '.', &option_tokens);
+
+ int properties_mask = 0;
+ int permissions_mask = 0;
+
+ if (std::find(option_tokens.begin(), option_tokens.end(), "notify") !=
+ option_tokens.end()) {
+ permissions_mask |= kPermissionRead;
+ properties_mask |= kPropertyRead;
+ properties_mask |= kPropertyNotify;
+ }
+ if (std::find(option_tokens.begin(), option_tokens.end(), "read") !=
+ option_tokens.end()) {
+ permissions_mask |= kPermissionRead;
+ properties_mask |= kPropertyRead;
+ }
+ if (std::find(option_tokens.begin(), option_tokens.end(), "write") !=
+ option_tokens.end()) {
+ permissions_mask |= kPermissionWrite;
+ properties_mask |= kPropertyWrite;
+ }
+
+ if (control_uuid.empty()) {
+ gatt_servers_[service_uuid]->AddCharacteristic(
+ UUID(characteristic_uuid), properties_mask, permissions_mask);
+ } else {
+ gatt_servers_[service_uuid]->AddBlob(UUID(characteristic_uuid),
+ UUID(control_uuid), properties_mask,
+ permissions_mask);
+ }
+ return true;
+}
+
+bool UnixIPCHost::OnSetCharacteristicValue(const std::string& service_uuid,
+ const std::string& characteristic_uuid,
+ const std::string& value) {
+ std::string decoded_data;
+ base::Base64Decode(value, &decoded_data);
+ std::vector<uint8_t> blob_data(decoded_data.begin(), decoded_data.end());
+ gatt_servers_[service_uuid]->SetCharacteristicValue(UUID(characteristic_uuid),
+ blob_data);
+ return true;
+}
+
+bool UnixIPCHost::OnSetAdvertisement(const std::string& service_uuid,
+ const std::string& advertise_uuids,
+ const std::string& advertise_data,
+ const std::string& manufacturer_data,
+ const std::string& transmit_name) {
+ 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;
+ base::SplitString(advertise_uuids, '.', &advertise_uuid_tokens);
+
+ // string -> vector<UUID>
+ std::vector<UUID> ids;
+ for (const auto& uuid_token : advertise_uuid_tokens)
+ ids.emplace_back(uuid_token);
+
+ std::string decoded_data;
+ base::Base64Decode(advertise_data, &decoded_data);
+ std::vector<uint8_t> decoded_advertise_data(decoded_data.begin(),
+ decoded_data.end());
+
+ base::Base64Decode(manufacturer_data, &decoded_data);
+ std::vector<uint8_t> decoded_manufacturer_data(decoded_data.begin(),
+ decoded_data.end());
+
+ gatt_servers_[service_uuid]->SetAdvertisement(ids, decoded_advertise_data,
+ decoded_manufacturer_data,
+ TokenBool(transmit_name));
+ return true;
+}
+
+bool UnixIPCHost::OnSetScanResponse(const std::string& service_uuid,
+ const std::string& scan_response_uuids,
+ const std::string& scan_response_data,
+ const std::string& manufacturer_data,
+ const std::string& transmit_name) {
+ std::vector<std::string> scan_response_uuid_tokens;
+ base::SplitString(scan_response_uuids, '.', &scan_response_uuid_tokens);
+
+ // string -> vector<UUID>
+ std::vector<UUID> ids;
+ for (const auto& uuid_token : scan_response_uuid_tokens)
+ ids.emplace_back(uuid_token);
+
+ std::string decoded_data;
+ base::Base64Decode(scan_response_data, &decoded_data);
+ std::vector<uint8_t> decoded_advertise_data(decoded_data.begin(),
+ decoded_data.end());
+
+ base::Base64Decode(manufacturer_data, &decoded_data);
+ std::vector<uint8_t> decoded_manufacturer_data(decoded_data.begin(),
+ decoded_data.end());
+
+ gatt_servers_[service_uuid]->SetScanResponse(ids, decoded_advertise_data,
+ decoded_manufacturer_data,
+ TokenBool(transmit_name));
+ return true;
+}
+
+bool UnixIPCHost::OnStartService(const std::string& service_uuid) {
+ return gatt_servers_[service_uuid]->Start();
+}
+
+bool UnixIPCHost::OnStopService(const std::string& service_uuid) {
+ return gatt_servers_[service_uuid]->Stop();
+}
+
+bool UnixIPCHost::OnMessage() {
+ std::string ipc_msg;
+ int size = recv(pfds_[kFdIpc].fd, &ipc_msg[0], 0, MSG_PEEK | MSG_TRUNC);
+ if (-1 == size) {
+ LOG_ERROR(LOG_TAG, "Error reading datagram size: %s", strerror(errno));
+ return false;
+ } else if (0 == size) {
+ LOG_INFO(LOG_TAG, "%s:%d: Connection closed", __func__, __LINE__);
+ return false;
+ }
+
+ ipc_msg.resize(size);
+ size = read(pfds_[kFdIpc].fd, &ipc_msg[0], ipc_msg.size());
+ if (-1 == size) {
+ LOG_ERROR(LOG_TAG, "Error reading IPC: %s", strerror(errno));
+ return false;
+ } else if (0 == size) {
+ LOG_INFO(LOG_TAG, "%s:%d: Connection closed", __func__, __LINE__);
+ return false;
+ }
+
+ std::vector<std::string> tokens;
+ base::SplitString(ipc_msg, '|', &tokens);
+ switch (tokens.size()) {
+ case 2:
+ if (tokens[0] == kSetAdapterNameCommand)
+ return OnSetAdapterName(tokens[1]);
+ if (tokens[0] == kCreateServiceCommand)
+ return OnCreateService(tokens[1]);
+ if (tokens[0] == kDestroyServiceCommand)
+ return OnDestroyService(tokens[1]);
+ if (tokens[0] == kStartServiceCommand)
+ return OnStartService(tokens[1]);
+ if (tokens[0] == kStopServiceCommand)
+ return OnStopService(tokens[1]);
+ break;
+ case 4:
+ if (tokens[0] == kSetCharacteristicValueCommand)
+ return OnSetCharacteristicValue(tokens[1], tokens[2], tokens[3]);
+ break;
+ case 5:
+ if (tokens[0] == kAddCharacteristicCommand)
+ return OnAddCharacteristic(tokens[1], tokens[2], tokens[3], tokens[4]);
+ break;
+ case 6:
+ if (tokens[0] == kSetAdvertisementCommand)
+ return OnSetAdvertisement(tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
+ if (tokens[0] == kSetScanResponseCommand)
+ return OnSetScanResponse(tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]);
+ break;
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "Malformed IPC message: %s", ipc_msg.c_str());
+ return false;
+}
+
+bool UnixIPCHost::OnGattWrite() {
+ UUID::UUID128Bit id;
+ int r = read(pfds_[kFdGatt].fd, id.data(), id.size());
+ if (r != id.size()) {
+ LOG_ERROR(LOG_TAG, "Error reading GATT attribute ID");
+ return false;
+ }
+
+ std::vector<uint8_t> value;
+ // TODO(icoolidge): Generalize this for multiple clients.
+ auto server = gatt_servers_.begin();
+ server->second->GetCharacteristicValue(UUID(id), &value);
+ const std::string value_string(value.begin(), value.end());
+ std::string encoded_value;
+ base::Base64Encode(value_string, &encoded_value);
+
+ std::string transmit(kWriteCharacteristicCommand);
+ transmit += "|" + server->first;
+ transmit += "|" + base::HexEncode(id.data(), id.size());
+ transmit += "|" + encoded_value;
+
+ r = write(pfds_[kFdIpc].fd, transmit.data(), transmit.size());
+ if (-1 == r) {
+ LOG_ERROR(LOG_TAG, "Error replying to IPC: %s", strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace ipc
--- /dev/null
+//
+// 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
+
+#include <poll.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "service/gatt_server.h"
+#include "service/uuid.h"
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+
+// This implements a single threaded event loop which dispatches
+// reads from a set of FDs (pfds_) to a set of handlers.
+// Reads from the GATT pipe read end will result in a write to
+// to the IPC socket, and vise versa.
+class UnixIPCHost {
+ public:
+ // UnixIPCHost owns the passed sockfd.
+ UnixIPCHost(int sockfd, bluetooth::Adapter* adapter);
+ ~UnixIPCHost();
+
+ // Synchronously handle all events on input FDs.
+ bool EventLoop();
+
+ private:
+ // Handler for IPC message receives.
+ // Decodes protocol and dispatches to another handler.
+ bool OnMessage();
+
+ // Handler for GATT characteristic writes.
+ // Encodes to protocol and transmits IPC.
+ bool OnGattWrite();
+
+ // Applies adapter name changes to stack.
+ bool OnSetAdapterName(const std::string& name);
+
+ // Handles service creation.
+ bool OnCreateService(const std::string& service_uuid);
+
+ // Handles service destruction.
+ bool OnDestroyService(const std::string& service_uuid);
+
+ // Creates a characteristic for a service.
+ bool OnAddCharacteristic(const std::string& service_uuid,
+ const std::string& characteristic_uuid,
+ const std::string& control_uuid,
+ const std::string& options);
+
+ // Sets the value of a characetistic.
+ bool OnSetCharacteristicValue(const std::string& service_uuid,
+ const std::string& characteristic_uuid,
+ const std::string& value);
+
+ // Applies settings to service advertisement.
+ bool OnSetAdvertisement(const std::string& service_uuid,
+ const std::string& advertise_uuids,
+ const std::string& advertise_data,
+ const std::string& manufacturer_data,
+ const std::string& transmit_name);
+
+ // Applies settings to scan response.
+ bool OnSetScanResponse(const std::string& service_uuid,
+ const std::string& advertise_uuids,
+ const std::string& advertise_data,
+ const std::string& manufacturer_data,
+ const std::string& transmit_name);
+
+ // Starts service (advertisement and connections)
+ bool OnStartService(const std::string& service_uuid);
+
+ // Stops service.
+ bool OnStopService(const std::string& service_uuid);
+
+ // weak reference.
+ bluetooth::Adapter *adapter_;
+
+ // File descripters that we will block against.
+ std::vector<struct pollfd> pfds_;
+
+ // Container for multiple GATT servers. Currently only one is supported.
+ // TODO(icoolidge): support many to one for real.
+ std::unordered_map<std::string, std::unique_ptr<bluetooth::gatt::Server>>
+ gatt_servers_;
+};
+
+} // namespace ipc
--- /dev/null
+//
+// 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.
+//
+#include "logging_helpers.h"
+
+#include <string.h>
+
+#include <string>
+
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
+const char *BtAvConnectionStateText(const btav_connection_state_t state) {
+ switch (state) {
+ CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_DISCONNECTED);
+ CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_CONNECTING);
+ CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_CONNECTED);
+ CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_DISCONNECTING);
+ default:
+ return "Invalid AV connection state";
+ }
+}
+
+const char *BtAvAudioStateText(const btav_audio_state_t state) {
+ switch (state) {
+ CASE_RETURN_TEXT(BTAV_AUDIO_STATE_REMOTE_SUSPEND);
+ CASE_RETURN_TEXT(BTAV_AUDIO_STATE_STOPPED);
+ CASE_RETURN_TEXT(BTAV_AUDIO_STATE_STARTED);
+ default:
+ return "Invalid audio state";
+ }
+}
+
+const char *BtTransportText(const btgatt_transport_t t) {
+ switch(t) {
+ CASE_RETURN_TEXT(GATT_TRANSPORT_AUTO);
+ CASE_RETURN_TEXT(GATT_TRANSPORT_BREDR);
+ CASE_RETURN_TEXT(GATT_TRANSPORT_LE);
+ default:
+ return "unknown transport";
+ }
+}
+
+const char *BtStateText(const bt_state_t state) {
+ switch (state) {
+ CASE_RETURN_TEXT(BT_STATE_OFF);
+ CASE_RETURN_TEXT(BT_STATE_ON);
+ default:
+ return "unknown state code";
+ }
+}
+
+const char *BtScanModeText(const bt_scan_mode_t mode) {
+ switch (mode) {
+ CASE_RETURN_TEXT(BT_SCAN_MODE_NONE);
+ CASE_RETURN_TEXT(BT_SCAN_MODE_CONNECTABLE);
+ CASE_RETURN_TEXT(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ default:
+ return "unknown scan mode";
+ }
+}
+
+const char *BtStatusText(const bt_status_t status) {
+ switch (status) {
+ CASE_RETURN_TEXT(BT_STATUS_SUCCESS);
+ CASE_RETURN_TEXT(BT_STATUS_FAIL);
+ CASE_RETURN_TEXT(BT_STATUS_NOT_READY);
+ CASE_RETURN_TEXT(BT_STATUS_NOMEM);
+ CASE_RETURN_TEXT(BT_STATUS_DONE);
+ CASE_RETURN_TEXT(BT_STATUS_BUSY);
+ CASE_RETURN_TEXT(BT_STATUS_UNSUPPORTED);
+ CASE_RETURN_TEXT(BT_STATUS_PARM_INVALID);
+ CASE_RETURN_TEXT(BT_STATUS_UNHANDLED);
+ CASE_RETURN_TEXT(BT_STATUS_AUTH_FAILURE);
+ CASE_RETURN_TEXT(BT_STATUS_RMT_DEV_DOWN);
+ CASE_RETURN_TEXT(BT_STATUS_AUTH_REJECTED);
+ default:
+ return "unknown status code";
+ }
+}
+
+const char *BtPropertyText(const bt_property_type_t prop) {
+ switch (prop) {
+ CASE_RETURN_TEXT(BT_PROPERTY_BDNAME);
+ CASE_RETURN_TEXT(BT_PROPERTY_BDADDR);
+ CASE_RETURN_TEXT(BT_PROPERTY_UUIDS);
+ CASE_RETURN_TEXT(BT_PROPERTY_CLASS_OF_DEVICE);
+ CASE_RETURN_TEXT(BT_PROPERTY_TYPE_OF_DEVICE);
+ CASE_RETURN_TEXT(BT_PROPERTY_SERVICE_RECORD);
+ CASE_RETURN_TEXT(BT_PROPERTY_ADAPTER_SCAN_MODE);
+ CASE_RETURN_TEXT(BT_PROPERTY_ADAPTER_BONDED_DEVICES);
+ CASE_RETURN_TEXT(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT);
+ CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_FRIENDLY_NAME);
+ CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_RSSI);
+ CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_VERSION_INFO);
+ CASE_RETURN_TEXT(BT_PROPERTY_LOCAL_LE_FEATURES);
+ CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP);
+ default:
+ return "Invalid property";
+ }
+}
+
+const char *BtEventText(const bt_cb_thread_evt evt) {
+ switch (evt) {
+ CASE_RETURN_TEXT(ASSOCIATE_JVM);
+ CASE_RETURN_TEXT(DISASSOCIATE_JVM);
+ default:
+ return "unknown state code";
+ }
+}
+
+const char *BtAclText(const bt_acl_state_t code) {
+ switch (code) {
+ CASE_RETURN_TEXT(BT_ACL_STATE_CONNECTED);
+ CASE_RETURN_TEXT(BT_ACL_STATE_DISCONNECTED);
+ default:
+ return "unknown ACL code";
+ }
+}
+
+std::string BtAddrString(const bt_bdaddr_t *addr) {
+ char buffer[20];
+ snprintf(buffer, sizeof(buffer), "%02X:%02X:%02X:%02X:%02X:%02X",
+ addr->address[0], addr->address[1], addr->address[2],
+ addr->address[3], addr->address[4], addr->address[5]);
+ return std::string(buffer);
+}
--- /dev/null
+//
+// 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
+
+#include <string.h>
+
+#include <string>
+
+#include "hardware/bluetooth.h"
+#include "hardware/bt_av.h"
+#include "hardware/bt_gatt_types.h"
+
+const char *BtAvConnectionStateText(const btav_connection_state_t state);
+
+const char *BtAvAudioStateText(const btav_audio_state_t state);
+
+const char *BtTransportText(const btgatt_transport_t t);
+
+const char *BtStateText(const bt_state_t state);
+
+const char *BtScanModeText(const bt_scan_mode_t mode);
+
+const char *BtStatusText(const bt_status_t status);
+
+const char *BtPropertyText(const bt_property_type_t prop);
+
+const char *BtEventText(const bt_cb_thread_evt evt);
+
+const char *BtAclText(const bt_acl_state_t state);
+
+// TODO(icoolidge): Address object.
+std::string BtAddrString(const bt_bdaddr_t *addr);
--- /dev/null
+//
+// 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.
+//
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/files/scoped_file.h>
+
+// For system properties
+// TODO(icoolidge): abstraction or non-cutils stub.
+#if !defined(OS_GENERIC)
+#include <cutils/properties.h>
+#endif // !defined(OS_GENERIC)
+
+#include "service/daemon.h"
+#include "service/switches.h"
+
+namespace {
+
+// TODO(armansito): None of these should be hardcoded here. Instead, pass these
+// via commandline.
+const char kDisableProperty[] = "persist.bluetooth.disable";
+
+} // namespace
+
+int main(int argc, char *argv[]) {
+ base::AtExitManager exit_manager;
+ base::CommandLine::Init(argc, argv);
+
+ logging::LoggingSettings log_settings;
+ if (!logging::InitLogging(log_settings)) {
+ LOG(ERROR) << "Failed to set up logging";
+ return EXIT_FAILURE;
+ }
+
+ // TODO(armansito): Initialize base/logging. By default it will dump to stdout
+ // but we might want to change that based on a command-line switch. Figure out
+ // how to route the logging to Android's syslog. Once that's done, we won't
+ // need to use osi/include/log.h anymore.
+
+ // TODO(armansito): Register exit-time clean-up handlers for the IPC sockets.
+ // Register signal handlers.
+ auto command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(bluetooth::switches::kHelpLong) ||
+ command_line->HasSwitch(bluetooth::switches::kHelpShort)) {
+ LOG(INFO) << bluetooth::switches::kHelpMessage;
+ return EXIT_SUCCESS;
+ }
+
+#if !defined(OS_GENERIC)
+ // TODO(armansito): Remove Chromecast specific property out of here. This
+ // should just be obtained from global config.
+ char disable_value[PROPERTY_VALUE_MAX];
+ int status = property_get(kDisableProperty, disable_value, nullptr);
+ if (status && !strcmp(disable_value, "1")) {
+ LOG(INFO) << "service disabled";
+ return EXIT_SUCCESS;
+ }
+#endif // !defined(OS_GENERIC)
+
+ if (!bluetooth::Daemon::Initialize()) {
+ LOG(ERROR) << "Failed to initialize Daemon";
+ return EXIT_FAILURE;
+ }
+
+ // Start the main event loop.
+ bluetooth::Daemon::Get()->StartMainLoop();
+
+ // The main message loop has exited; clean up the Daemon.
+ bluetooth::Daemon::Get()->ShutDown();
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+//
+// 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.
+//
+
+#include "service/settings.h"
+
+#include <base/base_switches.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+
+#include "service/switches.h"
+
+namespace bluetooth {
+
+Settings::Settings()
+ : initialized_(false) {
+}
+
+Settings::~Settings() {
+}
+
+bool Settings::Init() {
+ CHECK(!initialized_);
+ auto command_line = base::CommandLine::ForCurrentProcess();
+ const auto& switches = command_line->GetSwitches();
+
+ for (const auto& iter : switches) {
+ if (iter.first == switches::kCreateIPCSocketPath) {
+ // kCreateIPCSocketPath: An optional argument that initializes an IPC
+ // socket path for IPC.
+ base::FilePath path(iter.second);
+ if (path.empty() || path.EndsWithSeparator()) {
+ LOG(ERROR) << "Invalid IPC create socket path";
+ return false;
+ }
+
+ create_ipc_socket_path_ = path;
+ } else if (iter.first == switches::kAndroidIPCSocketSuffix) {
+ // kAndroidIPCSocketSuffix: An optional argument used to express
+ // a socket that Android init created for us. We bind to this.
+ const std::string& suffix = iter.second;
+ if (suffix.empty()) {
+ LOG(ERROR) << "Invalid Android socket suffix";
+ return false;
+ }
+
+ android_ipc_socket_suffix_ = suffix;
+ }
+ // Check for libbase logging switches. These get processed by
+ // logging::InitLogging directly.
+ else if (iter.first != ::switches::kV) {
+ LOG(ERROR) << "Unexpected command-line switches found";
+ return false;
+ }
+ }
+
+ // Two IPC methods/paths were provided.
+ if (!android_ipc_socket_suffix_.empty() &&
+ !create_ipc_socket_path_.empty()) {
+ LOG(ERROR) << "Too many IPC methods provided";
+ return false;
+ }
+
+ // The daemon has no arguments
+ if (command_line->GetArgs().size()) {
+ LOG(ERROR) << "Unexpected command-line arguments found";
+ return false;
+ }
+
+ initialized_ = true;
+ return true;
+}
+
+} // namespace bluetooth
--- /dev/null
+//
+// 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
+
+#include <string>
+
+#include <base/files/file_path.h>
+#include <base/macros.h>
+
+namespace bluetooth {
+
+// The Settings class stores global runtime configurations, such as IPC domain
+// namespace, configuration file locations, and other system properties and
+// flags.
+class Settings {
+ public:
+ // Constant for the "--help" command-line switches.
+ static const char kHelp[];
+
+ Settings();
+ ~Settings();
+
+ // TODO(armansito): Write an instance method for storing things into a file.
+
+ // Initializes the Settings object. This reads the command-line options for
+ // the current process (which must have been initialized using
+ // base::CommandLine) and sets up the initial global settings. Returns false
+ // if there is an error, e.g. if the parameters/switches are malformed.
+ bool Init();
+
+ // If Android init created a server socket for the daemon,
+ // we can retrieve it through this suffix.
+ const std::string& android_ipc_socket_suffix() const {
+ return android_ipc_socket_suffix_;
+ }
+
+ // Path to create a Unix domain socket server for Bluetooth IPC.
+ const base::FilePath& create_ipc_socket_path() const {
+ return create_ipc_socket_path_;
+ }
+
+ // Returns true if domain-socket based IPC should be used. If false, then
+ // Binder IPC must be used.
+ inline bool UseSocketIPC() const {
+ return !android_ipc_socket_suffix().empty() ||
+ !create_ipc_socket_path().empty();
+ }
+
+ private:
+ bool initialized_;
+ std::string android_ipc_socket_suffix_;
+ base::FilePath create_ipc_socket_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(Settings);
+};
+
+} // namespace bluetooth
--- /dev/null
+//
+// 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
+
+#include <string>
+
+namespace bluetooth {
+namespace switches {
+
+// List of command-line switches used by the daemon.
+const char kHelpLong[] = "help";
+const char kHelpShort[] = "h";
+const char kAndroidIPCSocketSuffix[] = "android-ipc-socket-suffix";
+const char kCreateIPCSocketPath[] = "create-ipc-socket";
+
+const char kHelpMessage[] =
+ "\nBluetooth System Service\n"
+ "\n"
+ "Usage:\n"
+ "\t--help,-h\t\t\tShow this help message\n"
+ "\t--android-ipc-socket-suffix\tSuffix of socket created by Android init. "
+ "Mutually exclusive with --create-ipc-socket.\n"
+ "\t--create-ipc-socket\t\tSocket path created for Unix domain socket based "
+ "IPC. Mutually exclusive with --android-ipc-socket-suffix.\n"
+ "\t--v\t\t\t\tLog verbosity level (e.g. -v=1)\n";
+
+} // namespace switches
+} // namespace bluetooth
--- /dev/null
+//
+// 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.
+//
+
+#include <base/macros.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/hal/fake_bluetooth_interface.h"
+
+namespace bluetooth {
+namespace {
+
+class AdapterTest : public ::testing::Test {
+ public:
+ AdapterTest() = default;
+ ~AdapterTest() override = default;
+
+ void SetUp() override {
+ fake_hal_manager_ = hal::FakeBluetoothInterface::GetManager();
+ fake_hal_iface_ = new hal::FakeBluetoothInterface();
+ hal::BluetoothInterface::InitializeForTesting(fake_hal_iface_);
+
+ adapter_.reset(new Adapter());
+ }
+
+ void TearDown() override {
+ adapter_.reset();
+ hal::BluetoothInterface::CleanUp();
+ }
+
+ protected:
+ hal::FakeBluetoothInterface* fake_hal_iface_;
+ hal::FakeBluetoothInterface::Manager* fake_hal_manager_;
+ std::unique_ptr<Adapter> adapter_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AdapterTest);
+};
+
+class TestObserver final : public bluetooth::Adapter::Observer {
+ public:
+ TestObserver(bluetooth::Adapter* adapter)
+ : adapter_(adapter),
+ prev_state_(bluetooth::ADAPTER_STATE_INVALID),
+ cur_state_(bluetooth::ADAPTER_STATE_INVALID) {
+ CHECK(adapter_);
+ adapter_->AddObserver(this);
+ }
+
+ ~TestObserver() override {
+ adapter_->RemoveObserver(this);
+ }
+
+ bluetooth::AdapterState prev_state() const { return prev_state_; }
+ bluetooth::AdapterState cur_state() const { return cur_state_; }
+
+ // bluetooth::Adapter::Observer override:
+ void OnAdapterStateChanged(bluetooth::Adapter* adapter,
+ bluetooth::AdapterState prev_state,
+ bluetooth::AdapterState new_state) {
+ ASSERT_EQ(adapter_, adapter);
+ prev_state_ = prev_state;
+ cur_state_ = new_state;
+ }
+
+ private:
+ bluetooth::Adapter* adapter_;
+ bluetooth::AdapterState prev_state_, cur_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestObserver);
+};
+
+TEST_F(AdapterTest, IsEnabled) {
+ EXPECT_FALSE(adapter_->IsEnabled());
+
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+ EXPECT_TRUE(adapter_->IsEnabled());
+
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_OFF);
+ EXPECT_FALSE(adapter_->IsEnabled());
+}
+
+TEST_F(AdapterTest, Enable) {
+ TestObserver observer(adapter_.get());
+
+ EXPECT_FALSE(adapter_->IsEnabled());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+ // Enable fails at HAL level
+ EXPECT_FALSE(adapter_->Enable());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+ // Enable success
+ fake_hal_manager_->enable_succeed = true;
+ EXPECT_TRUE(adapter_->Enable());
+
+ // Should have received a state update.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, observer.cur_state());
+
+ // Enable fails because not disabled
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, adapter_->GetState());
+ EXPECT_FALSE(adapter_->Enable());
+
+ // Adapter state updates properly
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, adapter_->GetState());
+
+ // Should have received a state update.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+ // Enable fails because already enabled
+ EXPECT_FALSE(adapter_->Enable());
+}
+
+TEST_F(AdapterTest, Disable) {
+ TestObserver observer(adapter_.get());
+
+ fake_hal_manager_->disable_succeed = true;
+ EXPECT_FALSE(adapter_->IsEnabled());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+ // Disable fails because already disabled
+ EXPECT_FALSE(adapter_->Disable());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+ // Disable success
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+
+ // Should have received a state update.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+ EXPECT_TRUE(adapter_->Disable());
+
+ // Should have received a state update.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, observer.cur_state());
+
+ // Disable fails because not enabled
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, adapter_->GetState());
+ EXPECT_FALSE(adapter_->Disable());
+
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, adapter_->GetState());
+
+ // Should have received a state update.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+ // Disable fails at HAL level
+ fake_hal_manager_->disable_succeed = false;
+ EXPECT_FALSE(adapter_->Disable());
+
+ // Should have received a state update. In this case we will receive two
+ // updates: one going from OFF to TURNING_OFF, and one going from TURNING_OFF
+ // back to ON since we failed to initiate the disable operation.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+ // Update state to OFF. Should receive a state update.
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_OFF);
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.cur_state());
+}
+
+TEST_F(AdapterTest, GetName) {
+ EXPECT_EQ(bluetooth::Adapter::kDefaultName, adapter_->GetName());
+
+ const char kTestAdapterName[] = "Test Adapter Name";
+
+ fake_hal_iface_->NotifyAdapterNamePropertyChanged(kTestAdapterName);
+ EXPECT_EQ(kTestAdapterName, adapter_->GetName());
+}
+
+TEST_F(AdapterTest, SetName) {
+ bt_bdname_t hal_name;
+
+ // Name too large.
+ EXPECT_FALSE(adapter_->SetName(std::string(sizeof(hal_name.name), 'a')));
+
+ // Valid length.
+ EXPECT_FALSE(adapter_->SetName("Test Name"));
+ fake_hal_manager_->set_property_succeed = true;
+ EXPECT_TRUE(adapter_->SetName("Test Name"));
+}
+
+TEST_F(AdapterTest, GetAddress) {
+ EXPECT_EQ(bluetooth::Adapter::kDefaultAddress, adapter_->GetAddress());
+
+ const bt_bdaddr_t kTestAdapterInput = {
+ { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc }
+ };
+ const char kTestAdapterAddressOutput[] = "12:34:56:78:9A:BC";
+
+ fake_hal_iface_->NotifyAdapterAddressPropertyChanged(&kTestAdapterInput);
+ EXPECT_EQ(kTestAdapterAddressOutput, adapter_->GetAddress());
+}
+
+} // namespace
+} // namespace bluetooth
--- /dev/null
+//
+// 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.
+//
+
+extern "C" {
+
+// TODO(armansito): This provides a fake implementation of the function defined
+// in btcore/include/hal_util.h. We have to provide this to prevent having to
+// pull in libbtcore and transitively libhardware as dependencies for the unit
+// tests. Instead of doing it this way, however, we should instead provide a C++
+// class abstraction for this (and all other btif interfaces) that we can mock
+// for testing.
+int hal_util_load_bt_library(const struct hw_module_t** module) {
+ return -1;
+}
+
+} // extern "C"
--- /dev/null
+//
+// 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.
+//
+
+#include <memory>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/files/scoped_file.h>
+#include <base/macros.h>
+#include <base/strings/stringprintf.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/hal/fake_bluetooth_interface.h"
+#include "service/ipc/ipc_manager.h"
+#include "service/settings.h"
+#include "service/test/mock_daemon.h"
+
+
+namespace {
+
+using testing::Return;
+
+const char kTestSocketPath[] = "test_socket_path";
+
+class IPCUnixTest : public ::testing::Test {
+ public:
+ IPCUnixTest() = default;
+ ~IPCUnixTest() override = default;
+
+ void SetUp() override {
+ SetUpCommandLine();
+ ASSERT_TRUE(settings_.Init());
+
+ auto mock_daemon = new bluetooth::testing::MockDaemon();
+
+ ON_CALL(*mock_daemon, GetSettings()).WillByDefault(Return(&settings_));
+ ON_CALL(*mock_daemon, GetMessageLoop())
+ .WillByDefault(Return(&message_loop_));
+
+ bluetooth::Daemon::InitializeForTesting(mock_daemon);
+ bluetooth::hal::BluetoothInterface::InitializeForTesting(
+ new bluetooth::hal::FakeBluetoothInterface());
+
+ adapter_.reset(new bluetooth::Adapter());
+ ipc_manager_.reset(new ipc::IPCManager(adapter_.get()));
+ }
+
+ void TearDown() override {
+ client_fd_.reset();
+ ipc_manager_.reset();
+ adapter_.reset();
+ bluetooth::hal::BluetoothInterface::CleanUp();
+ bluetooth::Daemon::ShutDown();
+ base::CommandLine::Reset();
+ }
+
+ virtual void SetUpCommandLine() {
+ std::string ipc_socket_arg =
+ base::StringPrintf("--create-ipc-socket=%s", kTestSocketPath);
+ const base::CommandLine::CharType* argv[] = {
+ "program", ipc_socket_arg.c_str(),
+ };
+ base::CommandLine::Init(arraysize(argv), argv);
+ }
+
+ void ConnectToTestSocket() {
+ client_fd_.reset(socket(PF_UNIX, SOCK_SEQPACKET, 0));
+ ASSERT_TRUE(client_fd_.is_valid());
+
+ struct sockaddr_un address;
+ memset(&address, 0, sizeof(address));
+ address.sun_family = AF_UNIX;
+ strncpy(address.sun_path, kTestSocketPath, sizeof(address.sun_path) - 1);
+
+ int status = connect(client_fd_.get(), (struct sockaddr *)&address,
+ sizeof(address));
+ EXPECT_EQ(0, status);
+ }
+
+ protected:
+ base::AtExitManager exit_manager_;
+ base::MessageLoop message_loop_;
+ bluetooth::Settings settings_;
+
+ std::unique_ptr<bluetooth::Adapter> adapter_;
+ std::unique_ptr<ipc::IPCManager> ipc_manager_;
+ base::ScopedFD client_fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCUnixTest);
+};
+
+class IPCUnixTestDisabled : public IPCUnixTest {
+ public:
+ IPCUnixTestDisabled() = default;
+ ~IPCUnixTestDisabled() override = default;
+
+ void SetUpCommandLine() override {
+ // Set up with no --ipc-socket-path
+ const base::CommandLine::CharType* argv[] = { "program" };
+ base::CommandLine::Init(arraysize(argv), argv);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IPCUnixTestDisabled);
+};
+
+class TestDelegate : public ipc::IPCManager::Delegate,
+ public base::SupportsWeakPtr<TestDelegate> {
+ public:
+ TestDelegate() : started_count_(0), stopped_count_(0) {
+ }
+
+ void OnIPCHandlerStarted(ipc::IPCManager::Type type) override {
+ ASSERT_EQ(ipc::IPCManager::TYPE_UNIX, type);
+ started_count_++;
+ base::MessageLoop::current()->Quit();
+ }
+
+ void OnIPCHandlerStopped(ipc::IPCManager::Type type) override {
+ ASSERT_EQ(ipc::IPCManager::TYPE_UNIX, type);
+ stopped_count_++;
+ base::MessageLoop::current()->Quit();
+ }
+
+ int started_count() const { return started_count_; }
+ int stopped_count() const { return stopped_count_; }
+
+ private:
+ int started_count_;
+ int stopped_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+TEST_F(IPCUnixTestDisabled, StartWithNoSocketPath) {
+ TestDelegate delegate;
+ EXPECT_FALSE(ipc_manager_->Start(ipc::IPCManager::TYPE_UNIX, &delegate));
+ EXPECT_FALSE(ipc_manager_->UnixStarted());
+ EXPECT_EQ(0, delegate.started_count());
+ EXPECT_EQ(0, delegate.stopped_count());
+}
+
+TEST_F(IPCUnixTest, BasicStartAndExit) {
+ TestDelegate delegate;
+ EXPECT_TRUE(ipc_manager_->Start(ipc::IPCManager::TYPE_UNIX, &delegate));
+ EXPECT_TRUE(ipc_manager_->UnixStarted());
+
+ // Run the message loop. We will stop the loop when we receive a delegate
+ // event.
+ message_loop_.Run();
+
+ // We should have received the started event.
+ EXPECT_EQ(1, delegate.started_count());
+ EXPECT_EQ(0, delegate.stopped_count());
+
+ // At this point the thread is blocking on accept and listening for incoming
+ // connections. TearDown should gracefully clean up the thread and the test
+ // should succeed without hanging.
+ ipc_manager_.reset();
+ message_loop_.Run();
+ EXPECT_EQ(1, delegate.stopped_count());
+}
+
+TEST_F(IPCUnixTest, BasicStartAndConnect) {
+ TestDelegate delegate;
+ EXPECT_TRUE(ipc_manager_->Start(ipc::IPCManager::TYPE_UNIX, &delegate));
+ EXPECT_TRUE(ipc_manager_->UnixStarted());
+
+ // Run the message loop. We will stop the loop when we receive a delegate
+ // event.
+ message_loop_.Run();
+
+ // We should have received the started event.
+ EXPECT_EQ(1, delegate.started_count());
+ EXPECT_EQ(0, delegate.stopped_count());
+
+ // IPC successfully started. Now attempt to connect to the socket.
+ ConnectToTestSocket();
+
+ // TODO(armansito): Test that the IPC event loop shuts down cleanly while a
+ // client is connected. Currently this will fail and the fix is to use
+ // MessageLoopForIO rather than a custom event loop.
+}
+
+} // namespace
--- /dev/null
+//
+// 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
+
+#include <gmock/gmock.h>
+
+#include "service/daemon.h"
+
+namespace bluetooth {
+namespace testing {
+
+class MockDaemon : public Daemon {
+ public:
+ MockDaemon() = default;
+ ~MockDaemon() override = default;
+
+ MOCK_CONST_METHOD0(GetSettings, Settings*());
+ MOCK_CONST_METHOD0(GetMessageLoop, base::MessageLoop*());
+ MOCK_METHOD0(StartMainLoop, void());
+ MOCK_METHOD0(Init, bool());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockDaemon);
+};
+
+} // namespace testing
+} // namespace bluetooth
--- /dev/null
+//
+// 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.
+//
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/macros.h>
+#include <gtest/gtest.h>
+
+#include "service/settings.h"
+#include "service/switches.h"
+
+using bluetooth::Settings;
+using namespace bluetooth::switches;
+
+namespace {
+
+class SettingsTest : public ::testing::Test {
+ public:
+ SettingsTest() = default;
+
+ void TearDown() override {
+ base::CommandLine::Reset();
+ }
+
+ protected:
+ base::AtExitManager exit_manager_;
+ Settings settings_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SettingsTest);
+};
+
+TEST_F(SettingsTest, EmptyCommandLine) {
+ const base::CommandLine::CharType* argv[] = { "program" };
+ base::CommandLine::Init(arraysize(argv), argv);
+ EXPECT_TRUE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedSwitches1) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "--create-ipc-socket=foobar", "--foobarbaz"
+ };
+ base::CommandLine::Init(arraysize(argv), argv);
+ EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedSwitches2) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "--foobarbaz"
+ };
+ base::CommandLine::Init(arraysize(argv), argv);
+ EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedArguments1) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "foobarbaz"
+ };
+ base::CommandLine::Init(arraysize(argv), argv);
+ EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedArguments2) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "--create-ipc-socket=foobar", "foobarbaz"
+ };
+ base::CommandLine::Init(arraysize(argv), argv);
+ EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, TooManyIpcOptions) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "--create-ipc-socket=foobar",
+ "--android-ipc-socket-suffix=foobar"};
+ base::CommandLine::Init(arraysize(argv), argv);
+ EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, GoodArgumentsCreateIpc) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "--create-ipc-socket=foobar"
+ };
+ base::CommandLine::Init(arraysize(argv), argv);
+ EXPECT_TRUE(settings_.Init());
+}
+
+TEST_F(SettingsTest, GoodArgumentsAndroidIpc) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "--android-ipc-socket-suffix=foobar"
+ };
+ base::CommandLine::Init(arraysize(argv), argv);
+ EXPECT_TRUE(settings_.Init());
+}
+
+} // namespace
--- /dev/null
+//
+// 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.
+//
+
+#include "service/ipc/binder/ipc_handler_binder.h"
+
+// TODO(armansito): This is a crappy workaround to link IPCHandlerBinder into
+// host-native unit tests. We should instead figure out a way to build Binder
+// unit tests for host.
+
+namespace ipc {
+
+IPCHandlerBinder::IPCHandlerBinder(
+ bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate)
+ : IPCHandler(adapter, delegate) {
+ // Stub
+}
+
+IPCHandlerBinder::~IPCHandlerBinder() {
+ // Stub
+}
+
+bool IPCHandlerBinder::Run() {
+ // Stub
+ return false;
+}
+
+void IPCHandlerBinder::Stop() {
+ // Stub
+}
+
+void IPCHandlerBinder::NotifyStarted() {
+ // Stub
+}
+
+} // namespace
--- /dev/null
+//
+// 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.
+//
+#include <algorithm>
+#include <array>
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+#include "service/uuid.h"
+
+using namespace bluetooth;
+
+namespace {
+
+const std::array<uint8_t, UUID::kUUID128Octets> kBtSigBaseUUID = {
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, }
+};
+
+} // namespace
+
+// Verify that an uninitialized UUID is equal
+// To the BT SIG Base UUID.
+TEST(UUIDTest, DefaultUUID) {
+ UUID uuid;
+ ASSERT_TRUE(uuid.GetFullBigEndian() == kBtSigBaseUUID);
+}
+
+// Verify that we initialize a 16-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init16Bit) {
+ auto my_uuid_16 = kBtSigBaseUUID;
+ my_uuid_16[2] = 0xde;
+ my_uuid_16[3] = 0xad;
+ UUID uuid(UUID::UUID16Bit({{ 0xde, 0xad }}));
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
+}
+
+// Verify that we initialize a 16-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init16BitString) {
+ auto my_uuid_16 = kBtSigBaseUUID;
+ my_uuid_16[2] = 0xde;
+ my_uuid_16[3] = 0xad;
+ UUID uuid("dead");
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
+}
+
+
+// Verify that we initialize a 32-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init32Bit) {
+ auto my_uuid_32 = kBtSigBaseUUID;
+ my_uuid_32[0] = 0xde;
+ my_uuid_32[1] = 0xad;
+ my_uuid_32[2] = 0xbe;
+ my_uuid_32[3] = 0xef;
+ UUID uuid(UUID::UUID32Bit({{ 0xde, 0xad, 0xbe, 0xef }}));
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_32);
+}
+
+// Verify correct reading of a 32-bit UUID initialized from string.
+TEST(UUIDTest, Init32BitString) {
+ auto my_uuid_32 = kBtSigBaseUUID;
+ my_uuid_32[0] = 0xde;
+ my_uuid_32[1] = 0xad;
+ my_uuid_32[2] = 0xbe;
+ my_uuid_32[3] = 0xef;
+ UUID uuid("deadbeef");
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_32);
+}
+
+// Verify that we initialize a 128-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init128Bit) {
+ auto my_uuid_128 = kBtSigBaseUUID;
+ for (int i = 0; i < static_cast<int>(my_uuid_128.size()); ++i) {
+ my_uuid_128[i] = i;
+ }
+
+ UUID uuid(my_uuid_128);
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_128);
+}
+
+// Verify that we initialize a 128-bit UUID in a
+// way consistent with how we read it as LE.
+TEST(UUIDTest, Init128BitLittleEndian) {
+ auto my_uuid_128 = kBtSigBaseUUID;
+ for (int i = 0; i < static_cast<int>(my_uuid_128.size()); ++i) {
+ my_uuid_128[i] = i;
+ }
+
+ UUID uuid(my_uuid_128);
+ std::reverse(my_uuid_128.begin(), my_uuid_128.end());
+ ASSERT_TRUE(uuid.GetFullLittleEndian() == my_uuid_128);
+}
+
+// Verify that we initialize a 128-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init128BitString) {
+ auto my_uuid_128 = kBtSigBaseUUID;
+ for (int i = 0; i < static_cast<int>(my_uuid_128.size()); ++i) {
+ my_uuid_128[i] = i;
+ }
+
+ std::string uuid_text("000102030405060708090A0B0C0D0E0F");
+ ASSERT_TRUE(uuid_text.size() == (16 * 2));
+ UUID uuid(uuid_text);
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_128);
+}
--- /dev/null
+//
+// 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.
+//
+
+#include "service/util/atomic_string.h"
+
+namespace util {
+
+AtomicString::AtomicString(const std::string& str)
+ : str_(str) {
+}
+
+std::string AtomicString::Get() const {
+ std::mutex* mutex = const_cast<std::mutex*>(&lock_);
+ std::lock_guard<std::mutex> lock(*mutex);
+ return str_;
+}
+
+void AtomicString::Set(const std::string& str) {
+ std::lock_guard<std::mutex> lock(lock_);
+ str_ = str;
+}
+
+} // namespace util
--- /dev/null
+//
+// 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.
+//
+
+#include <mutex>
+#include <string>
+
+#include <base/macros.h>
+
+namespace util {
+
+// A simple atomic container class for std::string.
+class AtomicString final {
+ public:
+ AtomicString(const std::string& str);
+ ~AtomicString() = default;
+
+ std::string Get() const;
+ void Set(const std::string& str);
+
+ private:
+ std::mutex lock_;
+ std::string str_;
+
+ DISALLOW_COPY_AND_ASSIGN(AtomicString);
+};
+
+} // namespace util
--- /dev/null
+//
+// 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.
+//
+
+#include "service/uuid.h"
+
+#include <algorithm>
+#include <array>
+#include <stack>
+#include <string>
+
+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}};
+}
+
+UUID::UUID() {
+ InitializeDefault();
+}
+
+UUID::UUID(const std::string& uuid) {
+ InitializeDefault();
+ const int start_index = uuid.size() == 4 ? 2 : 0;
+ const size_t copy_size = std::min(id_.size(), uuid.size() / 2);
+ for (size_t i = 0; i < copy_size; ++i) {
+ std::string octet_text(uuid, i * 2, 2);
+ id_[start_index + i] = std::stoul(octet_text, 0, 16);
+ }
+}
+
+UUID::UUID(const bt_uuid_t& uuid) {
+ std::reverse_copy(uuid.uu, uuid.uu + sizeof(uuid.uu), id_.begin());
+}
+
+UUID::UUID(const UUID::UUID16Bit& uuid) {
+ InitializeDefault();
+ std::copy(uuid.begin(), uuid.end(), id_.begin() + kUUID16Octets);
+}
+
+UUID::UUID(const UUID::UUID32Bit& uuid) {
+ InitializeDefault();
+ std::copy(uuid.begin(), uuid.end(), id_.begin());
+}
+
+UUID::UUID(const UUID::UUID128Bit& uuid) : id_(uuid) {}
+
+const UUID::UUID128Bit UUID::GetFullBigEndian() const {
+ return id_;
+}
+
+const UUID::UUID128Bit UUID::GetFullLittleEndian() const {
+ UUID::UUID128Bit ret;
+ std::reverse_copy(id_.begin(), id_.end(), ret.begin());
+ return ret;
+}
+
+const bt_uuid_t UUID::GetBlueDroid() const {
+ bt_uuid_t ret;
+ std::reverse_copy(id_.begin(), id_.end(), ret.uu);
+ return ret;
+}
+
+bool UUID::operator<(const UUID& rhs) const {
+ return std::lexicographical_compare(id_.begin(), id_.end(), rhs.id_.begin(),
+ rhs.id_.end());
+}
+
+bool UUID::operator==(const UUID& rhs) const {
+ return std::equal(id_.begin(), id_.end(), rhs.id_.begin());
+}
+
+} // namespace bluetooth
--- /dev/null
+//
+// 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
+
+#include <array>
+#include <string>
+
+#include "hardware/bluetooth.h"
+
+namespace bluetooth {
+
+class UUID {
+ public:
+ enum Type {
+ kUUID128Octets = 16,
+ kUUID32Octets = 4,
+ kUUID16Octets = 2,
+ };
+
+ typedef std::array<uint8_t, UUID::kUUID16Octets> UUID16Bit;
+ typedef std::array<uint8_t, UUID::kUUID32Octets> UUID32Bit;
+ typedef std::array<uint8_t, UUID::kUUID128Octets> UUID128Bit;
+
+ // Construct a Bluetooth 'base' UUID.
+ UUID();
+
+ // BlueDroid constructor.
+ explicit UUID(const bt_uuid_t& uuid);
+
+ // String constructor. Only hex ASCII accepted.
+ explicit UUID(const std::string& uuid);
+
+ // std::array variants constructors.
+ explicit UUID(const UUID::UUID16Bit& uuid);
+ explicit UUID(const UUID::UUID32Bit& uuid);
+ explicit UUID(const UUID::UUID128Bit& uuid);
+
+ // Provide the full network-byte-ordered blob.
+ const UUID128Bit GetFullBigEndian() const;
+
+ // Provide blob in Little endian (BlueDroid expects this).
+ const UUID128Bit GetFullLittleEndian() const;
+
+ // Helper for bluedroid LE type.
+ const bt_uuid_t GetBlueDroid() const;
+
+ bool operator<(const UUID& rhs) const;
+ bool operator==(const UUID& rhs) const;
+
+ private:
+ void InitializeDefault();
+ // Network-byte-ordered ID.
+ UUID128Bit id_;
+};
+
+} // namespace bluetooth
--- /dev/null
+#
+# 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.
+#
+
+static_library("stack") {
+ sources = [
+ "a2dp/a2d_api.c",
+ "a2dp/a2d_sbc.c",
+ "avrc/avrc_api.c",
+ "avrc/avrc_sdp.c",
+ "avrc/avrc_opt.c",
+ "avrc/avrc_bld_tg.c",
+ "avrc/avrc_bld_ct.c",
+ "avrc/avrc_pars_tg.c",
+ "avrc/avrc_pars_ct.c",
+ "avrc/avrc_utils.c",
+ "hid/hidh_api.c",
+ "hid/hidh_conn.c",
+ "bnep/bnep_main.c",
+ "bnep/bnep_utils.c",
+ "bnep/bnep_api.c",
+ "hcic/hciblecmds.c",
+ "hcic/hcicmds.c",
+ "btm/btm_ble.c",
+ "btm/btm_sec.c",
+ "btm/btm_inq.c",
+ "btm/btm_ble_addr.c",
+ "btm/btm_ble_bgconn.c",
+ "btm/btm_main.c",
+ "btm/btm_dev.c",
+ "btm/btm_ble_gap.c",
+ "btm/btm_ble_adv_filter.c",
+ "btm/btm_ble_multi_adv.c",
+ "btm/btm_ble_batchscan.c",
+ "btm/btm_ble_cont_energy.c",
+ "btm/btm_ble_privacy.c",
+ "btm/btm_acl.c",
+ "btm/btm_sco.c",
+ "btm/btm_pm.c",
+ "btm/btm_devctl.c",
+ "rfcomm/rfc_utils.c",
+ "rfcomm/port_rfc.c",
+ "rfcomm/rfc_l2cap_if.c",
+ "rfcomm/rfc_mx_fsm.c",
+ "rfcomm/port_utils.c",
+ "rfcomm/rfc_port_fsm.c",
+ "rfcomm/rfc_port_if.c",
+ "rfcomm/port_api.c",
+ "rfcomm/rfc_ts_frames.c",
+ "mcap/mca_dact.c",
+ "mcap/mca_dsm.c",
+ "mcap/mca_l2c.c",
+ "mcap/mca_main.c",
+ "mcap/mca_csm.c",
+ "mcap/mca_cact.c",
+ "mcap/mca_api.c",
+ "gatt/gatt_sr.c",
+ "gatt/gatt_cl.c",
+ "gatt/gatt_api.c",
+ "gatt/gatt_auth.c",
+ "gatt/gatt_utils.c",
+ "gatt/gatt_main.c",
+ "gatt/att_protocol.c",
+ "gatt/gatt_attr.c",
+ "gatt/gatt_db.c",
+ "avct/avct_api.c",
+ "avct/avct_l2c.c",
+ "avct/avct_lcb.c",
+ "avct/avct_ccb.c",
+ "avct/avct_lcb_act.c",
+ "smp/smp_main.c",
+ "smp/smp_l2c.c",
+ "smp/smp_cmac.c",
+ "smp/smp_utils.c",
+ "smp/smp_act.c",
+ "smp/smp_keys.c",
+ "smp/smp_api.c",
+ "smp/aes.c",
+ "smp/smp_br_main.c",
+ "smp/p_256_curvepara.c",
+ "smp/p_256_ecc_pp.c",
+ "smp/p_256_multprecision.c",
+ "avdt/avdt_ccb.c",
+ "avdt/avdt_scb_act.c",
+ "avdt/avdt_msg.c",
+ "avdt/avdt_ccb_act.c",
+ "avdt/avdt_api.c",
+ "avdt/avdt_scb.c",
+ "avdt/avdt_ad.c",
+ "avdt/avdt_l2c.c",
+ "sdp/sdp_server.c",
+ "sdp/sdp_main.c",
+ "sdp/sdp_db.c",
+ "sdp/sdp_utils.c",
+ "sdp/sdp_api.c",
+ "sdp/sdp_discovery.c",
+ "pan/pan_main.c",
+ "srvc/srvc_battery.c",
+ "srvc/srvc_battery_int.h",
+ "srvc/srvc_dis.c",
+ "srvc/srvc_dis_int.h",
+ "srvc/srvc_eng.c",
+ "srvc/srvc_eng_int.h",
+ "pan/pan_api.c",
+ "pan/pan_utils.c",
+ "btu/btu_hcif.c",
+ "btu/btu_init.c",
+ "btu/btu_task.c",
+ "l2cap/l2c_fcr.c",
+ "l2cap/l2c_ucd.c",
+ "l2cap/l2c_main.c",
+ "l2cap/l2c_api.c",
+ "l2cap/l2c_utils.c",
+ "l2cap/l2c_csm.c",
+ "l2cap/l2c_link.c",
+ "l2cap/l2c_ble.c",
+ "l2cap/l2cap_client.c",
+ "gap/gap_api.c",
+ "gap/gap_ble.c",
+ "gap/gap_conn.c",
+ "gap/gap_utils.c",
+ ]
+
+ include_dirs = [
+ "include",
+ "avct",
+ "btm",
+ "avrc",
+ "l2cap",
+ "avdt",
+ "gatt",
+ "gap",
+ "pan",
+ "bnep",
+ "hid",
+ "sdp",
+ "smp",
+ "srvc",
+ "//btcore/include",
+ "//vnd/include",
+ "//vnd/ble",
+ "//btif/include",
+ "//hci/include",
+ "//include",
+ "//gki/common",
+ "//gki/ulinux",
+ "//osi/include",
+ "//udrv/include",
+ "//rpc/include",
+ "//hcis",
+ "//ctrlr/include",
+ "//bta/include",
+ "//bta/sys",
+ "//utils/include",
+ "//",
+ ]
+}
status = A2D_INVALID_PARAMS;
else
{
- losc = *p_info++;
- *p_info++;
+ losc = *p_info;
+ *p_info += 2;
+
/* If the function is called for the wrong Media Type or Media Codec Type */
if(losc != A2D_SBC_INFO_LEN || *p_info != A2D_MEDIA_CT_SBC)
status = A2D_WRONG_CODEC;
memcpy(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN);
GKI_init_q(&p_ccb->cmd_q);
GKI_init_q(&p_ccb->rsp_q);
- p_ccb->timer_entry.param = (UINT32) p_ccb;
+ p_ccb->timer_entry.param = p_ccb;
AVDT_TRACE_DEBUG("avdt_ccb_alloc %d", i);
break;
}
#endif
}
#endif
- p_scb->timer_entry.param = (UINT32) p_scb;
+ p_scb->timer_entry.param = p_scb;
AVDT_TRACE_DEBUG("avdt_scb_alloc hdl=%d, psc_mask:0x%x", i+1, p_cs->cfg.psc_mask);
break;
}
{
memset ((UINT8 *)p_bcb, 0, sizeof (tBNEP_CONN));
- p_bcb->conn_tle.param = (UINT32) p_bcb;
+ p_bcb->conn_tle.param = p_bcb;
memcpy ((UINT8 *)(p_bcb->rem_bda), (UINT8 *)p_rem_bda, BD_ADDR_LEN);
p_bcb->handle = xx + 1;
btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
}
BTM_TRACE_ERROR("btm_acl_encrypt_change: tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
- (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending);
+ PTR_TO_UINT(p_dev_rec), p_dev_rec->rs_disc_pending);
p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
}
#endif
btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
}
BTM_TRACE_ERROR("tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
- (UINT32)p_dev_rec, p_dev_rec->rs_disc_pending);
+ PTR_TO_UINT(p_dev_rec), p_dev_rec->rs_disc_pending);
p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
}
* security functions.
*
******************************************************************************/
+
+#define LOG_TAG "bt_btm_ble"
+
#include "bt_target.h"
#if BLE_INCLUDED == TRUE
#include <string.h>
#include "bt_types.h"
-#include "hcimsgs.h"
-#include "btu.h"
-#include "btm_int.h"
-#include "btm_ble_api.h"
-#include "smp_api.h"
-#include "l2c_int.h"
-#include "gap_api.h"
#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "btu.h"
#include "device/include/controller.h"
-
-#define LOG_TAG "bt_btm_ble"
+#include "gap_api.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
#include "osi/include/log.h"
+#include "smp_api.h"
#if SMP_INCLUDED == TRUE
extern BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length,
BTM_TRACE_DEBUG ("btm_find_dev_type - device_type = %d addr_type = %d", *p_dev_type , *p_addr_type);
}
-
/*******************************************************************************
**
** Function BTM_ReadConnectedTransportAddress
BOOLEAN BTM_ReadConnectedTransportAddress(BD_ADDR remote_bda, tBT_TRANSPORT transport)
{
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(remote_bda);
- tACL_CONN *p = btm_bda_to_acl(remote_bda, transport);
/* if no device can be located, return */
if (p_dev_rec == NULL)
return use_le;
}
-
/*******************************************************************************
**
** Function BTM_SetBleDataLength
}
}
-
#if (SMP_INCLUDED == TRUE)
/*******************************************************************************
}
/*******************************************************************************
-** Function btm_enc_proc_ltk
-** Description send LTK reply when it's ready.
-*******************************************************************************/
-static void btm_enc_proc_ltk(tSMP_ENC *p)
-{
- UINT8 i;
- BTM_TRACE_DEBUG ("btm_enc_proc_ltk");
- if (p && p->param_len == BT_OCTET16_LEN)
- {
- for (i = 0; i < (BT_OCTET16_LEN - btm_cb.key_size); i ++)
- p->param_buf[BT_OCTET16_LEN - i - 1] = 0;
- btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, p->param_buf);
- }
-}
-
-/*******************************************************************************
-** Function btm_enc_proc_slave_y
-** Description calculate LTK when Y is ready
-*******************************************************************************/
-static void btm_enc_proc_slave_y(tSMP_ENC *p)
-{
- UINT16 div, y;
- UINT8 *pp = p->param_buf;
- tBTM_CB *p_cb = &btm_cb;
- tSMP_ENC output;
- tBTM_SEC_DEV_REC *p_dev_rec;
-
- BTM_TRACE_DEBUG ("btm_enc_proc_slave_y");
- if (p != NULL)
- {
- STREAM_TO_UINT16(y, pp);
-
- div = p_cb->ediv ^ y;
- p_dev_rec = btm_find_dev_by_handle (p_cb->enc_handle);
-
- if ( p_dev_rec &&
- p_dev_rec->ble.keys.div == div )
- {
- BTM_TRACE_DEBUG ("LTK request OK");
- /* calculating LTK , LTK = E er(div) */
- SMP_Encrypt(p_cb->devcb.ble_encryption_key_value, BT_OCTET16_LEN, (UINT8 *)&div, 2, &output);
- btm_enc_proc_ltk(&output);
- }
- else
- {
- BTM_TRACE_DEBUG ("LTK request failed - send negative reply");
- btsnd_hcic_ble_ltk_req_neg_reply(p_cb->enc_handle);
- if (p_dev_rec)
- btm_ble_link_encrypted(p_dev_rec->bd_addr, 0);
-
- }
- }
-}
-
-/*******************************************************************************
**
** Function btm_ble_ltk_request_reply
**
{
tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bda);
tBTM_CB *p_cb = &btm_cb;
- tSMP_ENC output;
if (p_rec == NULL)
{
if (match_rec)
{
- LOG_INFO("%s matched and resolved random address", __func__);
+ LOG_INFO(LOG_TAG, "%s matched and resolved random address", __func__);
match = TRUE;
match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA;
memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
}
else
{
- LOG_INFO("%s unable to match and resolve random address", __func__);
+ LOG_INFO(LOG_TAG, "%s unable to match and resolve random address", __func__);
}
btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match);
btm_ble_update_mode_operation(role, bda, status);
}
-
-
/*****************************************************************************
** Function btm_ble_create_ll_conn_complete
**
BTM_TRACE_DEBUG ("unknown event = %d", event);
break;
-
}
}
else
memcpy(&btm_cb.devcb.id_keys.ir[8], p->param_buf, BT_OCTET8_LEN);
/* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */
-
SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_dhk_pt,
1, &output);
btm_ble_process_dhk(&output);
if (adv_mode == BTM_BLE_ADV_ENABLE)
btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE);
-
}
/*******************************************************************************
#define LOG_TAG "bt_btm_ble"
#include <string.h>
+
#include "bt_target.h"
#if (BLE_INCLUDED == TRUE)
+
#include "bt_types.h"
-#include "hcimsgs.h"
-#include "btu.h"
-#include "btm_int.h"
#include "bt_utils.h"
-#include "hcidefs.h"
#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "btu.h"
#include "device/include/controller.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
#define BTM_BLE_ADV_FILT_META_HDR_LENGTH 3
#define BTM_BLE_ADV_FILT_FEAT_SELN_LEN 13
#define BTM_BLE_PF_BIT_TO_MASK(x) (UINT16)(1 << (x))
-
tBTM_BLE_ADV_FILTER_CB btm_ble_adv_filt_cb;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
static const BD_ADDR na_bda= {0};
#define BTM_BLE_GET_SCAN_PF_ACTION(x) ((x) & 0x0f)
#define BTM_BLE_INVALID_COUNTER 0xff
-
/* length of each multi adv sub command */
#define BTM_BLE_ADV_FILTER_ENB_LEN 3
return st;
}
-
/*******************************************************************************
**
** Function btm_ble_update_srvc_data_change
return BTM_BLE_INVALID_COUNTER;
}
-
/*******************************************************************************
**
** Function btm_ble_update_addr_filter
return st;
}
-
/*******************************************************************************
**
** Function btm_ble_clear_scan_pf_filter
#endif
if (!btsnd_hcic_ble_set_scan_enable(TRUE, TRUE)) /* duplicate filtering enabled */
return FALSE;
+
/* mark up inquiry status flag */
p_cb->scan_activity |= BTM_LE_SELECT_CONN_ACTIVE;
p_cb->wl_state |= BTM_BLE_WL_SCAN;
*
******************************************************************************/
+#define LOG_TAG "bt_btm_ble"
+
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include "bt_types.h"
#include "bt_utils.h"
-#include "btm_int.h"
#include "btm_ble_api.h"
+#include "btm_int.h"
#include "btu.h"
#include "device/include/controller.h"
-#include "hcimsgs.h"
#include "gap_api.h"
+#include "hcimsgs.h"
#if BLE_INCLUDED == TRUE
-#include "l2c_int.h"
-
-#include "gattdefs.h"
-#include "gatt_int.h"
#include "btm_ble_int.h"
-#define LOG_TAG "bt_btm_ble"
+#include "gatt_int.h"
+#include "gattdefs.h"
+#include "l2c_int.h"
#include "osi/include/log.h"
#define BTM_BLE_NAME_SHORT 0x01
/* check LE combo state supported */
#define BTM_LE_STATES_SUPPORTED(x, y, z) ((x)[(z)] & (y))
-
/*******************************************************************************
**
** Function BTM_BleUpdateAdvWhitelist
return status;
}
+#if BLE_VND_INCLUDED == TRUE
/*******************************************************************************
**
** Function btm_vsc_brcm_features_complete
*******************************************************************************/
static void btm_ble_vendor_capability_vsc_cmpl_cback (tBTM_VSC_CMPL *p_vcs_cplt_params)
{
-#if BLE_VND_INCLUDED == TRUE
UINT8 status = 0xFF;
UINT8 *p;
if (btm_cb.cmn_ble_vsc_cb.max_irk_list_sz > 0 &&
controller_get_interface()->get_ble_resolving_list_max_size() == 0)
btm_ble_resolving_list_init(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz);
-#endif
+#endif /* (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) */
if (btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg > 0)
btm_ble_batchscan_init();
if (p_ctrl_le_feature_rd_cmpl_cback != NULL)
p_ctrl_le_feature_rd_cmpl_cback(status);
-#endif
}
+#endif /* BLE_VND_INCLUDED == TRUE */
/*******************************************************************************
**
UINT8 rsp_data[BTM_BLE_AD_DATA_LEN],
*p = rsp_data;
- BTM_TRACE_EVENT (" BTM_BleWriteScanRsp");
-
+ BTM_TRACE_EVENT ("%s: data_mask:%08x", __func__, data_mask);
if (!controller_get_interface()->supports_ble())
return BTM_ILLEGAL_VALUE;
UINT8 *p = p_adv;
UINT8 length;
UINT8 adv_type;
- BTM_TRACE_API("BTM_CheckAdvData type=0x%02X", type);
+ BTM_TRACE_API("%s: type=0x%02x", __func__, type);
STREAM_TO_UINT8(length, p);
#endif
/* manufacturer data */
if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_MANU &&
- p_data && p_data->p_manu &&
- p_data->p_manu->len != 0 && p_data->p_manu->p_val)
+ p_data && p_data->manu.len != 0)
{
- if (p_data->p_manu->len > (len - MIN_ADV_LENGTH))
+ if (p_data->manu.len > (len - MIN_ADV_LENGTH))
cp_len = len - MIN_ADV_LENGTH;
else
- cp_len = p_data->p_manu->len;
+ cp_len = p_data->manu.len;
*p++ = cp_len + 1;
*p++ = BTM_BLE_AD_TYPE_MANU;
- ARRAY_TO_STREAM(p, p_data->p_manu->p_val, cp_len);
+ ARRAY_TO_STREAM(p, p_data->manu.val, cp_len);
len -= (cp_len + MIN_ADV_LENGTH);
data_mask &= ~BTM_BLE_AD_BIT_MANU;
}
/* 16 bits services */
if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE &&
- p_data && p_data->p_services &&
- p_data->p_services->num_service != 0 &&
- p_data->p_services->p_uuid)
+ p_data && p_data->services.num_service != 0)
{
- if (p_data->p_services->num_service * LEN_UUID_16 > (len - MIN_ADV_LENGTH))
+ if (p_data->services.num_service * LEN_UUID_16 > (len - MIN_ADV_LENGTH))
{
cp_len = (len - MIN_ADV_LENGTH)/LEN_UUID_16;
*p ++ = 1 + cp_len * LEN_UUID_16;
}
else
{
- cp_len = p_data->p_services->num_service;
+ cp_len = p_data->services.num_service;
*p++ = 1 + cp_len * LEN_UUID_16;
*p++ = BTM_BLE_AD_TYPE_16SRV_CMPL;
}
for (i = 0; i < cp_len; i ++)
{
- UINT16_TO_STREAM(p, *(p_data->p_services->p_uuid + i));
+ UINT16_TO_STREAM(p, *(p_data->services.uuid + i));
}
len -= (cp_len * MIN_ADV_LENGTH + MIN_ADV_LENGTH);
}
/* 32 bits service uuid */
if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE_32 &&
- p_data && p_data->p_service_32b &&
- p_data->p_service_32b->num_service != 0 &&
- p_data->p_service_32b->p_uuid)
+ p_data && p_data->service_32b.num_service != 0)
{
- if ((p_data->p_service_32b->num_service * LEN_UUID_32) > (len - MIN_ADV_LENGTH))
+ if ((p_data->service_32b.num_service * LEN_UUID_32) > (len - MIN_ADV_LENGTH))
{
cp_len = (len - MIN_ADV_LENGTH)/LEN_UUID_32;
*p ++ = 1 + cp_len * LEN_UUID_32;
}
else
{
- cp_len = p_data->p_service_32b->num_service;
+ cp_len = p_data->service_32b.num_service;
*p++ = 1 + cp_len * LEN_UUID_32;
*p++ = BTM_BLE_AD_TYPE_32SRV_CMPL;
}
for (i = 0; i < cp_len; i ++)
{
- UINT32_TO_STREAM(p, *(p_data->p_service_32b->p_uuid + i));
+ UINT32_TO_STREAM(p, *(p_data->service_32b.uuid + i));
}
len -= (cp_len * LEN_UUID_32 + MIN_ADV_LENGTH);
}
/* 128 bits services */
if (len >= (MAX_UUID_SIZE + 2) && data_mask & BTM_BLE_AD_BIT_SERVICE_128 &&
- p_data && p_data->p_services_128b)
+ p_data && p_data->services_128b.num_service)
{
*p ++ = 1 + MAX_UUID_SIZE;
- if (!p_data->p_services_128b->list_cmpl)
+ if (!p_data->services_128b.list_cmpl)
*p++ = BTM_BLE_AD_TYPE_128SRV_PART;
else
*p++ = BTM_BLE_AD_TYPE_128SRV_CMPL;
- ARRAY_TO_STREAM(p, p_data->p_services_128b->uuid128, MAX_UUID_SIZE);
+ ARRAY_TO_STREAM(p, p_data->services_128b.uuid128, MAX_UUID_SIZE);
len -= (MAX_UUID_SIZE + MIN_ADV_LENGTH);
data_mask &= ~BTM_BLE_AD_BIT_SERVICE_128;
}
/* 32 bits Service Solicitation UUIDs */
if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE_32SOL &&
- p_data && p_data->p_sol_service_32b &&
- p_data->p_sol_service_32b->num_service != 0 &&
- p_data->p_sol_service_32b->p_uuid)
+ p_data->sol_service_32b.num_service != 0)
{
- if ((p_data->p_sol_service_32b->num_service * LEN_UUID_32) > (len - MIN_ADV_LENGTH))
+ if ((p_data->sol_service_32b.num_service * LEN_UUID_32) > (len - MIN_ADV_LENGTH))
{
cp_len = (len - MIN_ADV_LENGTH)/LEN_UUID_32;
*p ++ = 1 + cp_len * LEN_UUID_32;
}
else
{
- cp_len = p_data->p_sol_service_32b->num_service;
+ cp_len = p_data->sol_service_32b.num_service;
*p++ = 1 + cp_len * LEN_UUID_32;
}
*p++ = BTM_BLE_AD_TYPE_32SOL_SRV_UUID;
for (i = 0; i < cp_len; i ++)
{
- UINT32_TO_STREAM(p, *(p_data->p_sol_service_32b->p_uuid + i));
+ UINT32_TO_STREAM(p, *(p_data->sol_service_32b.uuid + i));
}
len -= (cp_len * LEN_UUID_32 + MIN_ADV_LENGTH);
}
/* 128 bits Solicitation services UUID */
if (len >= (MAX_UUID_SIZE + MIN_ADV_LENGTH) && data_mask & BTM_BLE_AD_BIT_SERVICE_128SOL &&
- p_data && p_data->p_sol_service_128b)
+ p_data && p_data->sol_service_128b.num_service)
{
*p ++ = 1 + MAX_UUID_SIZE;
*p++ = BTM_BLE_AD_TYPE_128SOL_SRV_UUID;
- ARRAY_TO_STREAM(p, p_data->p_sol_service_128b->uuid128, MAX_UUID_SIZE);
+ ARRAY_TO_STREAM(p, p_data->sol_service_128b.uuid128, MAX_UUID_SIZE);
len -= (MAX_UUID_SIZE + MIN_ADV_LENGTH);
data_mask &= ~BTM_BLE_AD_BIT_SERVICE_128SOL;
}
/* 16bits/32bits/128bits Service Data */
if (len > MIN_ADV_LENGTH && data_mask & BTM_BLE_AD_BIT_SERVICE_DATA &&
- p_data && p_data->p_service_data->len != 0 && p_data->p_service_data->p_val)
+ p_data && p_data->service_data.len != 0)
{
- if (len > (p_data->p_service_data->service_uuid.len + MIN_ADV_LENGTH))
+ if (len > (p_data->service_data.service_uuid.len + MIN_ADV_LENGTH))
{
- if (p_data->p_service_data->len > (len - MIN_ADV_LENGTH))
- cp_len = len - MIN_ADV_LENGTH- p_data->p_service_data->service_uuid.len;
+ if (p_data->service_data.len > (len - MIN_ADV_LENGTH))
+ cp_len = len - MIN_ADV_LENGTH- p_data->service_data.service_uuid.len;
else
- cp_len = p_data->p_service_data->len;
+ cp_len = p_data->service_data.len;
- *p++ = cp_len + 1 + p_data->p_service_data->service_uuid.len;
- if (p_data->p_service_data->service_uuid.len == LEN_UUID_16)
+ *p++ = cp_len + 1 + p_data->service_data.service_uuid.len;
+ if (p_data->service_data.service_uuid.len == LEN_UUID_16)
{
*p++ = BTM_BLE_AD_TYPE_SERVICE_DATA;
- UINT16_TO_STREAM(p, p_data->p_service_data->service_uuid.uu.uuid16);
+ UINT16_TO_STREAM(p, p_data->service_data.service_uuid.uu.uuid16);
}
- else if (p_data->p_service_data->service_uuid.len == LEN_UUID_32)
+ else if (p_data->service_data.service_uuid.len == LEN_UUID_32)
{
*p++ = BTM_BLE_AD_TYPE_32SERVICE_DATA;
- UINT32_TO_STREAM(p, p_data->p_service_data->service_uuid.uu.uuid32);
+ UINT32_TO_STREAM(p, p_data->service_data.service_uuid.uu.uuid32);
}
else
{
*p++ = BTM_BLE_AD_TYPE_128SERVICE_DATA;
- ARRAY_TO_STREAM(p, p_data->p_service_data->service_uuid.uu.uuid128,
+ ARRAY_TO_STREAM(p, p_data->service_data.service_uuid.uu.uuid128,
LEN_UUID_128);
}
- ARRAY_TO_STREAM(p, p_data->p_service_data->p_val, cp_len);
+ ARRAY_TO_STREAM(p, p_data->service_data.val, cp_len);
- len -= (cp_len + MIN_ADV_LENGTH + p_data->p_service_data->service_uuid.len);
+ len -= (cp_len + MIN_ADV_LENGTH + p_data->service_data.service_uuid.len);
data_mask &= ~BTM_BLE_AD_BIT_SERVICE_DATA;
}
else
len -= 6;
data_mask &= ~BTM_BLE_AD_BIT_INT_RANGE;
}
- if (data_mask & BTM_BLE_AD_BIT_PROPRIETARY && p_data && p_data->p_proprietary)
+ if (data_mask & BTM_BLE_AD_BIT_PROPRIETARY && p_data)
{
- for (i = 0; i < p_data->p_proprietary->num_elem ; i ++)
+ for (i = 0; i < p_data->proprietary.num_elem; ++i)
{
- p_elem = p_data->p_proprietary->p_elem + i;
+ p_elem = &p_data->proprietary.elem[i];
if (len >= (MIN_ADV_LENGTH + p_elem->len))/* len byte(1) + ATTR type(1) + Uuid len(2)
+ value length */
{
*p ++ = p_elem->len + 1; /* Uuid len + value length */
*p ++ = p_elem->adv_type;
- ARRAY_TO_STREAM(p, p_elem->p_val, p_elem->len);
+ ARRAY_TO_STREAM(p, p_elem->val, p_elem->len);
len -= (MIN_ADV_LENGTH + p_elem->len);
}
btm_ble_update_dmt_flag_bits (&flag, connect_mode, disc_mode);
- LOG_DEBUG("disc_mode %04x", disc_mode);
+ LOG_DEBUG(LOG_TAG, "disc_mode %04x", disc_mode);
/* update discoverable flag */
if (disc_mode & BTM_BLE_LIMITED_DISCOVERABLE)
{
return status;
}
-
/*******************************************************************************
**
** Function btm_ble_start_inquiry
if ((result = btm_ble_is_discoverable(bda, evt_type, p)) == 0)
{
- LOG_WARN("%s device is no longer discoverable so discarding advertising packet pkt",
+ LOG_WARN(LOG_TAG, "%s device is no longer discoverable so discarding advertising packet pkt",
__func__);
return;
}
return rt;
}
-
/*******************************************************************************
**
** Function btm_ble_start_adv
return rt;
}
-
/*******************************************************************************
**
** Function btm_ble_start_slow_adv
}
}
-
/*******************************************************************************
**
** Function btm_ble_read_remote_features_complete
return rt;
}
-
#endif /* BLE_INCLUDED */
#if BLE_INCLUDED == TRUE
tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
tBTM_SEC_DEV_REC temp_rec = *p_target_rec;
- BD_ADDR dummy_bda = {0};
BTM_TRACE_DEBUG("%s", __func__);
*******************************************************************************/
static void btm_decode_ext_features_page (UINT8 page_number, const UINT8 *p_features)
{
- UINT8 last;
- UINT8 first;
-
BTM_TRACE_DEBUG ("btm_decode_ext_features_page page: %d", page_number);
switch (page_number)
{
#define LOG_TAG "bt_btm_pm"
+#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
#include "bt_types.h"
-#include "gki.h"
-#include "hcimsgs.h"
-#include "btu.h"
+#include "bt_utils.h"
#include "btm_api.h"
#include "btm_int.h"
-#include "l2c_int.h"
+#include "btu.h"
+#include "gki.h"
#include "hcidefs.h"
-#include "bt_utils.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
#include "osi/include/log.h"
/*****************************************************************************/
tBTM_PM_MODE mode;
int temp_pm_id;
-
if(pm_id >= BTM_MAX_PM_RECORDS)
pm_id = BTM_PM_SET_ONLY_ID;
return BTM_CMD_STORED;
}
-
-
return btm_pm_snd_md_req(pm_id, acl_ind, p_mode);
}
cb = btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback;
}
-
/* clear the register record */
for(xx=0; xx<BTM_MAX_PM_RECORDS; xx++)
{
BTM_TRACE_DEBUG("btm_pm_snd_md_req state:0x%x, link_ind: %d", p_cb->state, link_ind);
#endif // BTM_PM_DEBUG
- LOG_DEBUG("%s switching from %s to %s.", __func__, mode_to_string(p_cb->state), mode_to_string(md_res.mode));
+ LOG_DEBUG(LOG_TAG, "%s switching from %s to %s.", __func__, mode_to_string(p_cb->state), mode_to_string(md_res.mode));
switch(md_res.mode)
{
case BTM_PM_MD_ACTIVE:
}
}
-
/*******************************************************************************
**
** Function btm_pm_proc_cmd_status
p_cb->state = mode;
p_cb->interval = interval;
- LOG_DEBUG("%s switched from %s to %s.", __func__, mode_to_string(old_state), mode_to_string(p_cb->state));
+ LOG_DEBUG(LOG_TAG, "%s switched from %s to %s.", __func__, mode_to_string(old_state), mode_to_string(p_cb->state));
if ((p_lcb = l2cu_find_lcb_by_bd_addr(p->remote_addr, BT_TRANSPORT_BR_EDR)) != NULL)
{
}
}
-
/* notify registered parties */
for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
{
#include <string.h>
#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_int.h"
+#include "btu.h"
#include "device/include/controller.h"
#include "hcimsgs.h"
-#include "btu.h"
-#include "btm_int.h"
#include "l2c_int.h"
-#include "bt_utils.h"
#include "osi/include/log.h"
#if (BT_USE_TRACES == TRUE && BT_TRACE_VERBOSE == FALSE)
BOOLEAN (APPL_AUTH_WRITE_EXCEPTION)(BD_ADDR bd_addr);
#endif
-
/********************************************************************************
** L O C A L F U N C T I O N P R O T O T Y P E S *
*********************************************************************************/
static BOOLEAN btm_sec_queue_encrypt_request (BD_ADDR bd_addr, tBT_TRANSPORT transport,
tBTM_SEC_CALLBACK *p_callback, void *p_ref_data);
-static void btm_sec_clean_pending_req_queue (BD_ADDR remote_bda, tBT_TRANSPORT transport) ;
static void btm_sec_check_pending_enc_req (tBTM_SEC_DEV_REC *p_dev_rec, tBT_TRANSPORT transport,
UINT8 encr_enable);
-static BOOLEAN btm_sec_acceptor_rejects_bonding (tBTM_SEC_DEV_REC *p_dev_rec);
static BOOLEAN btm_sec_use_smp_br_chnl(tBTM_SEC_DEV_REC *p_dev_rec);
static BOOLEAN btm_sec_is_master(tBTM_SEC_DEV_REC *p_dev_rec);
BTM_TRACE_EVENT("%s application registered", __func__);
#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
- LOG_INFO("%s p_cb_info->p_le_callback == 0x%p", __func__, p_cb_info->p_le_callback);
+ LOG_INFO(LOG_TAG, "%s p_cb_info->p_le_callback == 0x%p", __func__, p_cb_info->p_le_callback);
if (p_cb_info->p_le_callback)
{
#if SMP_INCLUDED == TRUE
}
else
{
- LOG_WARN("%s p_cb_info->p_le_callback == NULL", __func__);
+ LOG_WARN(LOG_TAG, "%s p_cb_info->p_le_callback == NULL", __func__);
}
#endif
btm_cb.api = *p_cb_info;
#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
- LOG_INFO("%s btm_cb.api.p_le_callback = 0x%p ", __func__, btm_cb.api.p_le_callback);
+ LOG_INFO(LOG_TAG, "%s btm_cb.api.p_le_callback = 0x%p ", __func__, btm_cb.api.p_le_callback);
#endif
BTM_TRACE_EVENT("%s application registered", __func__);
return(TRUE);
return(FALSE);
}
-
/*******************************************************************************
**
** Function BTM_SecDeleteRmtNameNotifyCallback
p_srec = &btm_cb.sec_serv_rec[0];
-
for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++)
{
/* Check if there is already a record for this service */
#endif
#endif
-
return(record_allocated);
}
BTM_TRACE_DEBUG("btm_sec_bond_by_transport: Transport used %d" , transport);
-
/* Other security process is in progress */
if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)
{
p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED
| BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED);
-
BTM_TRACE_DEBUG ("after update sec_flags=0x%x", p_dev_rec->sec_flags);
if (!controller_get_interface()->supports_simple_pairing())
{
2046 may report HCI_Encryption_Change and L2C Connection Request out of sequence
because of data path issues. Delay this disconnect a little bit
*/
- LOG_INFO("%s peer should have initiated security process by now (SM4 to SM4)", __func__);
+ LOG_INFO(LOG_TAG, "%s peer should have initiated security process by now (SM4 to SM4)", __func__);
p_dev_rec->p_callback = p_callback;
p_dev_rec->sec_state = BTM_SEC_STATE_DELAY_FOR_ENC;
(*p_callback) (bd_addr, transport, p_ref_data, rc);
p_dev_rec = NULL;
}
-
/* Commenting out trace due to obf/compilation problems.
*/
#if (BT_USE_TRACES == TRUE)
p_dev_rec->sec_state = 0;
btm_cb.p_collided_dev_rec = p_dev_rec;
- btm_cb.sec_collision_tle.param = (UINT32) btm_sec_collision_timeout;
+ btm_cb.sec_collision_tle.param = UINT_TO_PTR(btm_sec_collision_timeout);
btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, BT_1SEC_TIMEOUT);
}
}
/* Start timer with 0 to initiate connection with new LCB */
/* because L2CAP will delete current LCB with this event */
btm_cb.p_collided_dev_rec = p_dev_rec;
- btm_cb.sec_collision_tle.param = (UINT32) btm_sec_connect_after_reject_timeout;
+ btm_cb.sec_collision_tle.param = UINT_TO_PTR(btm_sec_connect_after_reject_timeout);
btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, 0);
}
else
/* Start timer with 0 to initiate connection with new LCB */
/* because L2CAP will delete current LCB with this event */
btm_cb.p_collided_dev_rec = p_dev_rec;
- btm_cb.sec_collision_tle.param = (UINT32) btm_sec_connect_after_reject_timeout;
+ btm_cb.sec_collision_tle.param = UINT_TO_PTR(btm_sec_connect_after_reject_timeout);
btu_start_timer (&btm_cb.sec_collision_tle, BTU_TTYPE_USER_FUNC, 0);
}
p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
p_dev_rec->sec_flags &= ~ (BTM_SEC_LE_LINK_KEY_KNOWN << bit_shift);
-
#ifdef BRCM_NOT_4_BTE
/* If we rejected pairing, pass this special result code */
if (btm_cb.acl_disc_reason == HCI_ERR_HOST_REJECT_SECURITY)
p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
#if BTM_DISC_DURING_RS == TRUE
- LOG_INFO("%s clearing pending flag handle:%d reason:%d", __func__, handle, reason);
+ LOG_INFO(LOG_TAG, "%s clearing pending flag handle:%d reason:%d", __func__, handle, reason);
p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
#endif
p_inq_info->results.clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
}
-
/******************************************************************
** S T A T I C F U N C T I O N S
*******************************************************************/
return(BTM_SUCCESS);
}
-
/*******************************************************************************
**
** Function btm_sec_start_get_name
return(TRUE);
}
-
/*******************************************************************************
**
** Function btm_sec_start_authorization
return(NULL);
}
-
/*******************************************************************************
**
** Function btm_sec_find_next_serv
return(NULL);
}
-
/*******************************************************************************
**
** Function btm_sec_find_mx_serv
return(NULL);
}
-
/*******************************************************************************
**
** Function btm_sec_collision_timeout
}
}
-
/*******************************************************************************
**
** Function btm_sec_find_dev_by_sec_state
}
}
-
/*******************************************************************************
**
** Function btm_pair_state_descr
BTM_TRACE_API("%s: sm4: 0x%02x, rmt_support_for_secure_connections %d", __FUNCTION__,
p_dev_rec->sm4, p_dev_rec->remote_supports_secure_connections);
-
if (p_dev_rec->remote_features_needed)
{
BTM_TRACE_EVENT("%s: Now device in SC Only mode, waiting for peer remote features!",
/*******************************************************************************
**
-** Function btm_sec_clean_pending_req_queue
-**
-** Description This function cleans up the pending security request when the
-** link to the target device dropped.
-**
-** Returns void
-**
-*******************************************************************************/
-static void btm_sec_clean_pending_req_queue (BD_ADDR remote_bda, tBT_TRANSPORT transport)
-{
- tBTM_SEC_QUEUE_ENTRY *p_e;
- BUFFER_Q *bq = &btm_cb.sec_pending_q;
-
- p_e = (tBTM_SEC_QUEUE_ENTRY *)GKI_getfirst(bq);
-
- if (p_e != NULL)
- {
- if (memcmp(p_e->bd_addr, remote_bda, BD_ADDR_LEN) == 0
-#if BLE_INCLUDED == TRUE
- && p_e->transport == transport
-#endif
- )
- {
- (*p_e->p_callback) (remote_bda, transport, p_e->p_ref_data, BTM_ERR_PROCESSING);
- GKI_remove_from_queue(bq, (void *)p_e);
- }
- p_e = (tBTM_SEC_QUEUE_ENTRY *) GKI_getnext ((void *)p_e);
- }
-}
-
-/*******************************************************************************
-**
** Function btm_sec_is_serv_level0
**
** Description This function is called to check if the service corresponding
#define LOG_TAG "bt_btu_hcif"
#include <assert.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-#include "gki.h"
#include "bt_types.h"
-#include "hcimsgs.h"
-#include "btu.h"
-#include "l2c_int.h"
+#include "bt_utils.h"
#include "btm_api.h"
#include "btm_int.h"
-#include "bt_utils.h"
+#include "btu.h"
#include "device/include/controller.h"
+#include "gki.h"
+#include "hci_layer.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
#include "osi.h"
#include "osi/include/log.h"
-#include "hci_layer.h"
// TODO(zachoverflow): remove this horrible hack
#include "btu.h"
btu_hcif_qos_setup_comp_evt (p);
break;
case HCI_COMMAND_COMPLETE_EVT:
- LOG_ERROR("%s should not have received a command complete event. "
+ LOG_ERROR(LOG_TAG, "%s should not have received a command complete event. "
"Someone didn't go through the hci transmit_command function.", __func__);
break;
case HCI_COMMAND_STATUS_EVT:
- LOG_ERROR("%s should not have received a command status event. "
+ LOG_ERROR(LOG_TAG, "%s should not have received a command status event. "
"Someone didn't go through the hci transmit_command function.", __func__);
break;
case HCI_HARDWARE_ERROR_EVT:
}
}
-
/*******************************************************************************
**
** Function btu_hcif_send_cmd
#endif
}
-
/*******************************************************************************
**
** Function btu_hcif_send_host_rdy_for_data
btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK);
}
-
/*******************************************************************************
**
** Function btu_hcif_inquiry_result_evt
#endif /* BTM_SCO_INCLUDED */
}
-
/*******************************************************************************
**
** Function btu_hcif_connection_request_evt
#endif /* BTM_SCO_INCLUDED */
}
-
/*******************************************************************************
**
** Function btu_hcif_disconnection_comp_evt
btm_sec_auth_complete (handle, status);
}
-
/*******************************************************************************
**
** Function btu_hcif_rmt_name_request_comp_evt
btm_sec_rmt_name_request_complete (bd_addr, p, status);
}
-
/*******************************************************************************
**
** Function btu_hcif_encryption_change_evt
btm_read_remote_version_complete (p);
}
-
/*******************************************************************************
**
** Function btu_hcif_qos_setup_comp_evt
btm_qos_setup_complete(status, handle, &flow);
}
-
/*******************************************************************************
**
** Function btu_hcif_esco_connection_comp_evt
#endif
}
-
/*******************************************************************************
**
** Function btu_hcif_esco_connection_chg_evt
#endif
break;
-
case HCI_READ_INQ_TX_POWER_LEVEL:
btm_read_linq_tx_power_complete (p);
break;
fixed_queue_enqueue(btu_hci_msg_queue, event);
}
-
/*******************************************************************************
**
** Function btu_hcif_hdl_command_status
BTM_DeviceReset (NULL);
}
-
/*******************************************************************************
**
** Function btu_hcif_flush_occured_evt
{
}
-
/*******************************************************************************
**
** Function btu_hcif_role_change_evt
btm_acl_role_changed(status, bda, role);
}
-
/*******************************************************************************
**
** Function btu_hcif_num_compl_data_pkts_evt
btm_sec_pin_code_request (bda);
}
-
/*******************************************************************************
**
** Function btu_hcif_link_key_request_evt
btm_sec_link_key_request (bda);
}
-
/*******************************************************************************
**
** Function btu_hcif_link_key_notification_evt
btm_sec_link_key_notification (bda, key, key_type);
}
-
/*******************************************************************************
**
** Function btu_hcif_loopback_command_evt
{
}
-
/*******************************************************************************
**
** Function btu_hcif_data_buf_overflow_evt
{
}
-
/*******************************************************************************
**
** Function btu_hcif_max_slots_changed_evt
{
}
-
/*******************************************************************************
**
** Function btu_hcif_read_clock_off_comp_evt
btm_sec_update_clock_offset (handle, clock_offset);
}
-
/*******************************************************************************
**
** Function btu_hcif_conn_pkt_type_change_evt
{
}
-
/*******************************************************************************
**
** Function btu_hcif_qos_violation_evt
handle = HCID_GET_HANDLE (handle);
-
l2c_link_hci_qos_violation (handle);
}
-
/*******************************************************************************
**
** Function btu_hcif_page_scan_mode_change_evt
{
}
-
/*******************************************************************************
**
** Function btu_hcif_page_scan_rep_mode_chng_evt
btm_io_capabilities_req(p);
}
-
/*******************************************************************************
**
** Function btu_hcif_io_cap_response_evt
btm_io_capabilities_rsp(p);
}
-
/*******************************************************************************
**
** Function btu_hcif_user_conf_request_evt
btm_proc_sp_req_evt(BTM_SP_CFM_REQ_EVT, p);
}
-
/*******************************************************************************
**
** Function btu_hcif_user_passkey_request_evt
** End of Simple Pairing Events
***********************************************/
-
/**********************************************
** BLE Events
***********************************************/
#define LOG_TAG "bt_task"
#include <assert.h>
-
-#include "bt_target.h"
#include <pthread.h>
#include <string.h>
-#include "dyn_mem.h"
-#include "osi/include/alarm.h"
+#include "bt_target.h"
+#include "btm_int.h"
+#include "btu.h"
#include "device/include/controller.h"
+#include "dyn_mem.h"
+#include "l2c_int.h"
+#include "osi/include/alarm.h"
#include "osi/include/fixed_queue.h"
-#include "osi/include/hash_map.h"
-#include "btu.h"
-#include "btm_int.h"
#include "osi/include/hash_functions.h"
-#include "sdpint.h"
-#include "osi/include/thread.h"
-#include "l2c_int.h"
+#include "osi/include/hash_map.h"
#include "osi/include/log.h"
+#include "osi/include/thread.h"
+#include "sdpint.h"
#if (BLE_INCLUDED == TRUE)
#include "gatt_api.h"
return;
error_exit:;
- LOG_ERROR("%s Unable to allocate resources for bt_workqueue", __func__);
+ LOG_ERROR(LOG_TAG, "%s Unable to allocate resources for bt_workqueue", __func__);
BTU_ShutDown();
}
#define LOG_TAG "bt_btu_task"
#include <assert.h>
-#include <stdlib.h>
+#include <pthread.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include "osi/include/alarm.h"
#include "bt_target.h"
#include "bt_trace.h"
#include "bt_types.h"
#include "bt_utils.h"
+#include "btcore/include/module.h"
#include "btif_common.h"
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
-#include "osi/include/fixed_queue.h"
-#include "osi/include/future.h"
+#include "gap_int.h"
#include "gki.h"
-#include "osi/include/hash_map.h"
#include "hcimsgs.h"
#include "l2c_int.h"
-#include "btcore/include/module.h"
-#include "osi/include/osi.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/hash_map.h"
#include "osi/include/log.h"
-#include "sdpint.h"
+#include "osi/include/osi.h"
#include "osi/include/thread.h"
-
#include "port_api.h"
#include "port_ext.h"
-
-#include "gap_int.h"
+#include "sdpint.h"
#if (defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE)
#include "bnep_int.h"
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
"btu_task pending for preload complete event");
- LOG_INFO("Bluetooth chip preload is complete");
+ LOG_INFO(LOG_TAG, "Bluetooth chip preload is complete");
BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
"btu_task received preload complete event");
break;
#endif
-
#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)
case BTU_TTYPE_AVDT_CCB_RET:
case BTU_TTYPE_AVDT_CCB_RSP:
alarm_t *alarm = hash_map_get(btu_general_alarm_hash_map, p_tle);
if (alarm == NULL) {
- LOG_ERROR("%s Unable to create alarm", __func__);
+ LOG_ERROR(LOG_TAG, "%s Unable to create alarm", __func__);
return;
}
alarm_cancel(alarm);
// Get the alarm for the timer list entry.
alarm_t *alarm = hash_map_get(btu_general_alarm_hash_map, p_tle);
if (alarm == NULL) {
- LOG_WARN("%s Unable to find expected alarm in hashmap", __func__);
+ LOG_WARN(LOG_TAG, "%s Unable to find expected alarm in hashmap", __func__);
return;
}
alarm_cancel(alarm);
alarm_t *alarm = hash_map_get(btu_l2cap_alarm_hash_map, p_tle);
if (alarm == NULL) {
- LOG_ERROR("%s Unable to create alarm", __func__);
+ LOG_ERROR(LOG_TAG, "%s Unable to create alarm", __func__);
return;
}
alarm_cancel(alarm);
// Get the alarm for the timer list entry.
alarm_t *alarm = hash_map_get(btu_l2cap_alarm_hash_map, p_tle);
if (alarm == NULL) {
- LOG_WARN("%s Unable to find expected alarm in hashmap", __func__);
+ LOG_WARN(LOG_TAG, "%s Unable to find expected alarm in hashmap", __func__);
return;
}
alarm_cancel(alarm);
alarm_t *alarm = hash_map_get(btu_oneshot_alarm_hash_map, p_tle);
if (alarm == NULL) {
- LOG_ERROR("%s Unable to create alarm", __func__);
+ LOG_ERROR(LOG_TAG, "%s Unable to create alarm", __func__);
return;
}
alarm_cancel(alarm);
// Get the alarm for the timer list entry.
alarm_t *alarm = hash_map_get(btu_oneshot_alarm_hash_map, p_tle);
if (alarm == NULL) {
- LOG_WARN("%s Unable to find expected alarm in hashmap", __func__);
+ LOG_WARN(LOG_TAG, "%s Unable to find expected alarm in hashmap", __func__);
return;
}
alarm_cancel(alarm);
{
tGAP_CCB *p_ccb;
UINT16 cid;
- tBT_UUID bt_uuid = {2, {GAP_PROTOCOL_ID}};
GAP_TRACE_EVENT ("GAP_CONN - Open Request");
p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
/* Check if L2CAP started the connection process */
- if (p_rem_bda && ((cid = L2CA_CONNECT_REQ (p_ccb->psm, p_rem_bda, &p_ccb->ertm_info, &bt_uuid)) != 0))
+ if (p_rem_bda && ((cid = L2CA_CONNECT_REQ (p_ccb->psm, p_rem_bda, &p_ccb->ertm_info)) != 0))
{
p_ccb->connection_id = cid;
return (p_ccb->gap_handle);
{
UINT16 xx;
tGAP_CCB *p_ccb;
- tBT_UUID bt_uuid = {2, {GAP_PROTOCOL_ID}};
/* See if we have a CCB listening for the connection */
for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++)
p_ccb->connection_id = l2cap_cid;
/* Send response to the L2CAP layer. */
- L2CA_CONNECT_RSP (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK, &p_ccb->ertm_info, &bt_uuid);
+ L2CA_CONNECT_RSP (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK, &p_ccb->ertm_info);
GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x", p_ccb->connection_id);
*******************************************************************************/
void GATT_ConfigServiceChangeCCC (BD_ADDR remote_bda, BOOLEAN enable, tBT_TRANSPORT transport)
{
- UINT16 conn_id = GATT_INVALID_CONN_ID;
tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_bd_addr (remote_bda, transport);
if (p_clcb == NULL)
#include "hidh_int.h"
#include "bt_utils.h"
+#include "osi/include/osi.h"
+
static UINT8 find_conn_by_cid (UINT16 cid);
static void hidh_conn_retry (UINT8 dhandle);
*******************************************************************************/
void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle)
{
- hidh_conn_initiate( (UINT8) p_tle->param ) ;
- hh_cb.devices[p_tle->param].conn_tries++;
- hh_cb.callback( (UINT8) p_tle->param, hh_cb.devices[p_tle->param].addr,
- HID_HDEV_EVT_RETRYING, hh_cb.devices[p_tle->param].conn_tries, NULL ) ;
+ tHID_HOST_DEV_CTB *device;
+ UINT8 dhandle = PTR_TO_UINT(p_tle->param);
+
+ hidh_conn_initiate(dhandle);
+
+ device = &hh_cb.devices[dhandle];
+ device->conn_tries++;
+
+ hh_cb.callback(dhandle, device->addr, HID_HDEV_EVT_RETRYING,
+ device->conn_tries, NULL ) ;
}
/*******************************************************************************
{
tHID_HOST_DEV_CTB *p_dev = (tHID_HOST_DEV_CTB *) p_ref_data;
UINT8 dhandle;
- UINT32 reason;
UNUSED(bd_addr);
UNUSED (transport);
- dhandle = ((UINT32)p_dev - (UINT32)&(hh_cb.devices[0]))/ sizeof(tHID_HOST_DEV_CTB);
+ // TODO(armansito): This kind of math to determine a device handle is way
+ // too dirty and unnecessary. Why can't |p_dev| store it's handle?
+ dhandle = (PTR_TO_UINT(p_dev) - PTR_TO_UINT(&(hh_cb.devices[0])))/ sizeof(tHID_HOST_DEV_CTB);
if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
{
HIDH_TRACE_EVENT ("HID-Host Originator security pass.");
(hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE))
{
hh_cb.devices[dhandle].conn_tries = 0;
- hh_cb.devices[dhandle].conn.timer_entry.param = (UINT32) dhandle;
+ hh_cb.devices[dhandle].conn.timer_entry.param = UINT_TO_PTR(dhandle);
btu_start_timer (&(hh_cb.devices[dhandle].conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, disc_res, NULL);
}
tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
- p_dev->conn.timer_entry.param = (UINT32) dhandle;
+ p_dev->conn.timer_entry.param = UINT_TO_PTR(dhandle);
#if (HID_HOST_REPAGE_WIN > 0)
btu_start_timer (&(p_dev->conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
#else
#ifndef _AVRC_DEFS_H
#define _AVRC_DEFS_H
+#include "stack/include/bt_types.h"
+
/*****************************************************************************
** constants
*****************************************************************************/
#define AVRC_STS_ADDR_PLAYER_CHG 0x16 /* Addressed Player Changed - Register Notification */
typedef UINT8 tAVRC_STS;
-
/* Define the Capability IDs
*/
#define AVRC_CAP_COMPANY_ID 0x02
#define AVRC_MAX_CHARSET_SIZE 16
#define AVRC_MAX_ELEM_ATTR_SIZE 8
-
/*****************************************************************************
** Metadata transfer Building/Parsing definitions
*****************************************************************************/
UINT8 *p_str;
} tAVRC_NAME;
-
#ifndef AVRC_CAP_MAX_NUM_COMP_ID
#define AVRC_CAP_MAX_NUM_COMP_ID 4
#endif
UINT32 num_items;
} tAVRC_SEARCH_RSP;
-
typedef struct
{
UINT8 pdu;
tAVRC_RSP add_to_play; /* AddToNowPlaying */
} tAVRC_RESPONSE;
-
#endif
}tBTM_BLE_INT_RANGE;
/* Service tag supported in the device */
+#define MAX_16BIT_SERVICES 16
typedef struct
{
UINT8 num_service;
BOOLEAN list_cmpl;
- UINT16 *p_uuid;
+ UINT16 uuid[MAX_16BIT_SERVICES];
}tBTM_BLE_SERVICE;
/* 32 bits Service supported in the device */
+#define MAX_32BIT_SERVICES 4
typedef struct
{
UINT8 num_service;
BOOLEAN list_cmpl;
- UINT32 *p_uuid;
+ UINT32 uuid[MAX_32BIT_SERVICES];
}tBTM_BLE_32SERVICE;
/* 128 bits Service supported in the device */
typedef struct
{
+ UINT8 num_service;
BOOLEAN list_cmpl;
UINT8 uuid128[MAX_UUID_SIZE];
}tBTM_BLE_128SERVICE;
+#define MAX_SIZE_MANUFACTURER_DATA 32
typedef struct
{
- UINT8 len;
- UINT8 *p_val;
+ UINT8 len;
+ UINT8 val[MAX_SIZE_MANUFACTURER_DATA];
}tBTM_BLE_MANU;
-
+#define MAX_SIZE_SERVICE_DATA 32
typedef struct
{
tBT_UUID service_uuid;
UINT8 len;
- UINT8 *p_val;
+ UINT8 val[MAX_SIZE_SERVICE_DATA];
}tBTM_BLE_SERVICE_DATA;
+#define MAX_SIZE_PROPRIETARY_ELEMENT 32
typedef struct
{
UINT8 adv_type;
UINT8 len;
- UINT8 *p_val; /* number of len byte */
+ UINT8 val[MAX_SIZE_PROPRIETARY_ELEMENT]; /* number of len byte */
}tBTM_BLE_PROP_ELEM;
+#define MAX_PROPRIETARY_ELEMENTS 4
typedef struct
{
UINT8 num_elem;
- tBTM_BLE_PROP_ELEM *p_elem;
+ tBTM_BLE_PROP_ELEM elem[MAX_PROPRIETARY_ELEMENTS];
}tBTM_BLE_PROPRIETARY;
typedef struct
{
tBTM_BLE_INT_RANGE int_range; /* slave prefered conn interval range */
- tBTM_BLE_MANU *p_manu; /* manufactuer data */
- tBTM_BLE_SERVICE *p_services; /* services */
- tBTM_BLE_128SERVICE *p_services_128b; /* 128 bits service */
- tBTM_BLE_32SERVICE *p_service_32b; /* 32 bits Service UUID */
- tBTM_BLE_SERVICE *p_sol_services; /* 16 bits services Solicitation UUIDs */
- tBTM_BLE_32SERVICE *p_sol_service_32b; /* List of 32 bit Service Solicitation UUIDs */
- tBTM_BLE_128SERVICE *p_sol_service_128b; /* List of 128 bit Service Solicitation UUIDs */
- tBTM_BLE_PROPRIETARY *p_proprietary;
- tBTM_BLE_SERVICE_DATA *p_service_data; /* service data */
+ tBTM_BLE_MANU manu; /* manufactuer data */
+ tBTM_BLE_SERVICE services; /* services */
+ tBTM_BLE_128SERVICE services_128b; /* 128 bits service */
+ tBTM_BLE_32SERVICE service_32b; /* 32 bits Service UUID */
+ tBTM_BLE_SERVICE sol_services; /* 16 bits services Solicitation UUIDs */
+ tBTM_BLE_32SERVICE sol_service_32b; /* List of 32 bit Service Solicitation UUIDs */
+ tBTM_BLE_128SERVICE sol_service_128b; /* List of 128 bit Service Solicitation UUIDs */
+ tBTM_BLE_PROPRIETARY proprietary;
+ tBTM_BLE_SERVICE_DATA service_data; /* service data */
UINT16 appearance;
UINT8 flag;
UINT8 tx_power;
#define L2CA_REGISTER(a,b,c) L2CA_Register(a,(tL2CAP_APPL_INFO *)b)
#define L2CA_DEREGISTER(a) L2CA_Deregister(a)
-#define L2CA_CONNECT_REQ(a,b,c,d) L2CA_ErtmConnectReq(a,b,c)
-#define L2CA_CONNECT_RSP(a,b,c,d,e,f,g) L2CA_ErtmConnectRsp(a,b,c,d,e,f)
+#define L2CA_CONNECT_REQ(a,b,c) L2CA_ErtmConnectReq(a,b,c)
+#define L2CA_CONNECT_RSP(a,b,c,d,e,f) L2CA_ErtmConnectRsp(a,b,c,d,e,f)
#define L2CA_CONFIG_REQ(a,b) L2CA_ConfigReq(a,b)
#define L2CA_CONFIG_RSP(a,b) L2CA_ConfigRsp(a,b)
#define L2CA_DISCONNECT_REQ(a) L2CA_DisconnectReq(a)
#define LOG_TAG "bt_l2cap"
#include <assert.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-#include "gki.h"
#include "bt_types.h"
#include "btcore/include/counter.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "gki.h"
#include "hcidefs.h"
#include "hcimsgs.h"
-#include "l2cdefs.h"
#include "l2c_int.h"
-#include "btu.h"
-#include "btm_api.h"
+#include "l2cdefs.h"
#include "osi/include/allocator.h"
#include "osi/include/log.h"
return (vpsm);
}
-
-
/*******************************************************************************
**
** Function L2CA_Deregister
tL2C_CCB *channel_control_block = l2cu_find_ccb_by_cid(NULL, local_cid);
if (!channel_control_block) {
- LOG_ERROR("%s no channel control block found for L2CAP LCID=0x%04x.", __func__, local_cid);
+ LOG_ERROR(LOG_TAG, "%s no channel control block found for L2CAP LCID=0x%04x.", __func__, local_cid);
return false;
}
if (!channel_control_block->should_free_rcb) {
registration_control_block = (tL2C_RCB *)osi_calloc(sizeof(tL2C_RCB));
if (!registration_control_block) {
- LOG_ERROR("%s unable to allocate registration control block.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate registration control block.", __func__);
return false;
}
return L2CA_ErtmConnectRsp (p_bd_addr, id, lcid, result, status, NULL);
}
-
/*******************************************************************************
**
** Function L2CA_ErtmConnectRsp
return (TRUE);
}
-
/*******************************************************************************
**
** Function L2CA_ConfigReq
return (TRUE);
}
-
/*******************************************************************************
**
** Function L2CA_ConfigRsp
return (TRUE);
}
-
/*******************************************************************************
**
** Function L2CA_DisconnectReq
return (l2cb.l2cap_trace_level);
}
-
/*******************************************************************************
**
** Function L2CA_SetDesireRole
return (TRUE);
}
-
/*******************************************************************************
**
** Function L2CA_SetTxPriority
void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout)
{
- int i;
tL2C_LCB *p_lcb;
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bda);
void l2cble_advertiser_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout)
{
- int i;
tL2C_LCB *p_lcb;
tBTM_SEC_DEV_REC *p_dev_rec;
UNUSED(type);
static void l2cble_start_conn_update (tL2C_LCB *p_lcb)
{
UINT16 min_conn_int, max_conn_int, slave_latency, supervision_tout;
- tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev(p_lcb->remote_bd_addr);
tACL_CONN *p_acl_cb = btm_bda_to_acl(p_lcb->remote_bd_addr, BT_TRANSPORT_LE);
+ // TODO(armansito): The return value of this call wasn't being used but the
+ // logic of this function might be depending on its side effects. We should
+ // verify if this call is needed at all and remove it otherwise.
+ btm_find_or_alloc_dev(p_lcb->remote_bd_addr);
+
if (p_lcb->conn_update_mask & L2C_BLE_UPDATE_PENDING) return;
if (p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE)
*
******************************************************************************/
+#define LOG_TAG "bt_l2c_main"
+
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-#include "device/include/controller.h"
-#include "btcore/include/counter.h"
#include "bt_target.h"
+#include "btcore/include/counter.h"
#include "btm_int.h"
#include "btu.h"
+#include "device/include/controller.h"
#include "gki.h"
#include "hcimsgs.h"
#include "l2c_api.h"
}
}
-
/*******************************************************************************
**
** Function l2c_rcv_acl_data
}
break;
-
case L2CAP_CMD_DISC_REQ:
STREAM_TO_UINT16 (lcid, p);
STREAM_TO_UINT16 (rcid, p);
#endif
}
-
#if (L2CAP_NUM_FIXED_CHNLS > 0)
if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE)
{
btu_start_timer (&l2cb.rcv_hold_tle, BTU_TTYPE_L2CAP_HOLD, BT_1SEC_TIMEOUT);
}
-
/*******************************************************************************
**
** Function l2c_init
l2cb.non_flushable_pbf = L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT;
#endif
-
l2cb.p_free_ccb_first = &l2cb.ccb_pool[0];
l2cb.p_free_ccb_last = &l2cb.ccb_pool[MAX_L2CAP_CHANNELS - 1];
l2cb.rcv_pending_q = list_new(NULL);
if (l2cb.rcv_pending_q == NULL)
- LOG_ERROR("%s unable to allocate memory for link layer control block", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for link layer control block", __func__);
}
void l2c_free(void) {
#define LOG_TAG "bt_l2cap_client"
+#include "stack/include/l2cap_client.h"
+
#include <assert.h>
#include <string.h>
#include "osi/include/list.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
-#include "stack/include/l2cap_client.h"
#include "stack/include/l2c_api.h"
struct l2cap_client_t {
if (!l2cap_clients) {
l2cap_clients = list_new(NULL);
if (!l2cap_clients) {
- LOG_ERROR("%s unable to allocate space for L2CAP client list.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate space for L2CAP client list.", __func__);
return NULL;
}
}
l2cap_client_t *ret = (l2cap_client_t *)osi_calloc(sizeof(l2cap_client_t));
if (!ret) {
- LOG_ERROR("%s unable to allocate L2CAP client.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate L2CAP client.", __func__);
goto error;
}
ret->remote_mtu = L2CAP_MTU_DEFAULT;
ret->outbound_fragments = list_new(NULL);
if (!ret) {
- LOG_ERROR("%s unable to allocate outbound L2CAP fragment list.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to allocate outbound L2CAP fragment list.", __func__);
goto error;
}
client->local_channel_id = L2CA_ConnectReq(psm, (uint8_t *)remote_bdaddr);
if (!client->local_channel_id) {
- LOG_ERROR("%s unable to create L2CAP connection.", __func__);
+ LOG_ERROR(LOG_TAG, "%s unable to create L2CAP connection.", __func__);
return false;
}
assert(client != NULL);
if (client->local_channel_id && !L2CA_DisconnectReq(client->local_channel_id))
- LOG_ERROR("%s unable to send disconnect message for LCID 0x%04x.", __func__, client->local_channel_id);
+ LOG_ERROR(LOG_TAG, "%s unable to send disconnect message for LCID 0x%04x.", __func__, client->local_channel_id);
client->local_channel_id = 0;
client->remote_mtu = L2CAP_MTU_DEFAULT;
l2cap_client_t *client = find(local_channel_id);
if (!client) {
- LOG_ERROR("%s unable to find L2CAP client for LCID 0x%04x.", __func__, local_channel_id);
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client for LCID 0x%04x.", __func__, local_channel_id);
return;
}
if (error_code != L2CAP_CONN_OK) {
- LOG_ERROR("%s error connecting L2CAP channel: %d.", __func__, error_code);
+ LOG_ERROR(LOG_TAG, "%s error connecting L2CAP channel: %d.", __func__, error_code);
client->callbacks.disconnected(client, client->context);
return;
}
// Use default L2CAP parameters.
tL2CAP_CFG_INFO desired_parameters = { 0 };
if (!L2CA_ConfigReq(local_channel_id, &desired_parameters)) {
- LOG_ERROR("%s error sending L2CAP config parameters.", __func__);
+ LOG_ERROR(LOG_TAG, "%s error sending L2CAP config parameters.", __func__);
client->callbacks.disconnected(client, client->context);
}
}
l2cap_client_t *client = find(local_channel_id);
if (!client) {
- LOG_ERROR("%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
return;
}
}
if (!L2CA_ConfigRsp(local_channel_id, &response)) {
- LOG_ERROR("%s unable to send config response for LCID 0x%04x.", __func__, local_channel_id);
+ LOG_ERROR(LOG_TAG, "%s unable to send config response for LCID 0x%04x.", __func__, local_channel_id);
l2cap_client_disconnect(client);
return;
}
l2cap_client_t *client = find(local_channel_id);
if (!client) {
- LOG_ERROR("%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
return;
}
case L2CAP_CFG_UNACCEPTABLE_PARAMS:
// TODO: see if we can renegotiate parameters instead of dropping the connection.
- LOG_WARN("%s dropping L2CAP connection due to unacceptable config parameters.", __func__);
+ LOG_WARN(LOG_TAG, "%s dropping L2CAP connection due to unacceptable config parameters.", __func__);
l2cap_client_disconnect(client);
break;
// Failure, no further parameter negotiation possible.
default:
- LOG_WARN("%s L2CAP parameter negotiation failed with error code %d.", __func__, negotiated_parameters->result);
+ LOG_WARN(LOG_TAG, "%s L2CAP parameter negotiation failed with error code %d.", __func__, negotiated_parameters->result);
l2cap_client_disconnect(client);
break;
}
static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required) {
l2cap_client_t *client = find(local_channel_id);
if (!client) {
- LOG_ERROR("%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id);
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id);
return;
}
l2cap_client_t *client = find(local_channel_id);
if (!client) {
- LOG_ERROR("%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id);
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id);
return;
}
l2cap_client_t *client = find(local_channel_id);
if (!client) {
- LOG_ERROR("%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
return;
}
l2cap_client_t *client = find(local_channel_id);
if (!client) {
- LOG_ERROR("%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
return;
}
return;
case L2CAP_DW_FAILED:
- LOG_ERROR("%s error writing data to L2CAP connection LCID 0x%04x; disconnecting.", __func__, client->local_channel_id);
+ LOG_ERROR(LOG_TAG, "%s error writing data to L2CAP connection LCID 0x%04x; disconnecting.", __func__, client->local_channel_id);
l2cap_client_disconnect(client);
return;
*
******************************************************************************/
+#define LOG_TAG "bt_port_api"
+
+#include "port_api.h"
+
#include <string.h>
-#include "bt_target.h"
+
#include "btcore/include/counter.h"
+#include "btm_api.h"
+#include "btm_int.h"
#include "gki.h"
-#include "rfcdefs.h"
-#include "port_api.h"
+#include "l2c_api.h"
+#include "osi/include/log.h"
#include "port_int.h"
-#include "btm_int.h"
-#include "btm_api.h"
#include "rfc_int.h"
-#include "l2c_api.h"
+#include "rfcdefs.h"
#include "sdp_api.h"
-#include "osi/include/log.h"
/* duration of break in 200ms units */
#define PORT_BREAK_DURATION 1
-#define info(fmt, ...) LOG_INFO ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
-#define debug(fmt, ...) LOG_DEBUG ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
-#define error(fmt, ...) LOG_ERROR ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
-#define asrt(s) if(!(s)) LOG_ERROR ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+#define info(fmt, ...) LOG_INFO(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) LOG_DEBUG(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) LOG_ERROR(LOG_TAG, "## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) LOG_ERROR(LOG_TAG, "## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
/* Mapping from PORT_* result codes to human readable strings. */
static const char *result_code_strings[] = {
return port_open_continue (p_port);
}
-
/*******************************************************************************
**
** Function RFCOMM_RemoveConnection
return (PORT_SUCCESS);
}
-
-
/*******************************************************************************
**
** Function PORT_SetEventMask
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_CheckConnection
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_Control
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_FlowControl
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_GetModemStatus
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_ClearError
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_SendError
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_GetQueueStatus
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_Purge
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_ReadData
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_Read
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function port_write
return (PORT_UNKNOWN_ERROR);
}
-
RFCOMM_TRACE_EVENT ("PORT_WriteData %d bytes", length);
rc = port_write (p_port, p_buf);
return (PORT_SUCCESS);
}
-
-
/*******************************************************************************
**
** Function PORT_WriteData
return (PORT_SUCCESS);
}
-
/*******************************************************************************
**
** Function PORT_Test
RFCOMM_TRACE_EVENT ("rfc_timer_start - timeout:%d", timeout);
- p_tle->param = (UINT32)p_mcb;
+ p_tle->param = p_mcb;
btu_start_timer (p_tle, BTU_TTYPE_RFCOMM_MFC, timeout);
}
RFCOMM_TRACE_EVENT ("rfc_port_timer_start - timeout:%d", timeout);
- p_tle->param = (UINT32)p_port;
+ p_tle->param = p_port;
btu_start_timer (p_tle, BTU_TTYPE_RFCOMM_PORT, timeout);
}
#include "sdpint.h"
#include "btu.h"
+#include "osi/include/osi.h"
+
/**********************************************************************
** C L I E N T F U N C T I O N P R O T O T Y P E S *
***********************************************************************/
num_attr > SDP_MAX_ATTR_FILTERS || num_uuid > SDP_MAX_UUID_FILTERS)
{
SDP_TRACE_ERROR("SDP_InitDiscoveryDb Illegal param: p_db 0x%x, len %d, num_uuid %d, num_attr %d",
- (UINT32)p_db, len, num_uuid, num_attr);
+ PTR_TO_UINT(p_db), len, num_uuid, num_attr);
return(FALSE);
}
{
memset (p_ccb, 0, sizeof (tCONN_CB));
- p_ccb->timer_entry.param = (UINT32) p_ccb;
+ p_ccb->timer_entry.param = p_ccb;
return (p_ccb);
}
*
******************************************************************************/
+#define LOG_TAG "bt_srvc"
+
#include "bt_target.h"
#include "bt_utils.h"
#include "gatt_api.h"
#include "gatt_int.h"
-#include "srvc_eng_int.h"
-#include "srvc_dis_int.h"
-
-#define LOG_TAG "bt_srvc"
#include "osi/include/log.h"
+#include "srvc_dis_int.h"
+#include "srvc_eng_int.h"
#if BLE_INCLUDED == TRUE
#define STREAM_TO_UINT64(u64, p) {u64 = (((UINT64)(*(p))) + ((((UINT64)(*((p) + 1)))) << 8) + ((((UINT64)(*((p) + 2)))) << 16) + ((((UINT64)(*((p) + 3)))) << 24) \
+ ((((UINT64)(*((p) + 4)))) << 32) + ((((UINT64)(*((p) + 5)))) << 40) + ((((UINT64)(*((p) + 6)))) << 48) + ((((UINT64)(*((p) + 7)))) << 56)); (p) += 8;}
-
-
static const UINT16 dis_attr_uuid[DIS_MAX_CHAR_NUM] =
{
GATT_UUID_SYSTEM_ID,
}
break;
-
case GATT_UUID_SYSTEM_ID:
UINT64_TO_STREAM(p, dis_cb.dis_value.system_id); /* int_min */
p_value->len = DIS_SYSTEM_ID_SIZE;
if (dis_cb.p_read_dis_cback && p_clcb)
{
- LOG_INFO("%s conn_id:%d attr_mask = 0x%04x", __func__, conn_id,
+ LOG_INFO(LOG_TAG, "%s conn_id:%d attr_mask = 0x%04x", __func__, conn_id,
p_clcb->dis_value.attr_mask);
(*dis_cb.p_read_dis_cback)(p_clcb->bda, &p_clcb->dis_value);
dis_gatt_c_read_dis_req(conn_id);
}
-
/*******************************************************************************
**
** Function DIS_SrInit
(peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
(peer_bda[4]<<8)+peer_bda[5], dis_attr_uuid[dis_cb.dis_read_uuid_idx]);
-
GATT_GetConnIdIfConnected(srvc_eng_cb.gatt_if, peer_bda, &conn_id, BT_TRANSPORT_LE);
/* need to enhance it as multiple service is needed */
}
#endif /* BLE_INCLUDED */
-
#define SRVC_DIS_INT_H
#include "bt_target.h"
-#include "srvc_api.h"
#include "gatt_api.h"
+#include "srvc_api.h"
+#include "srvc_eng_int.h"
#define DIS_MAX_CHAR_NUM 9
-
typedef struct
{
UINT16 uuid;
#define DIS_SYSTEM_ID_SIZE 8
#define DIS_PNP_ID_SIZE 7
-
-
typedef struct
{
tDIS_DB_ENTRY dis_attr[DIS_MAX_CHAR_NUM];
tDIS_ATTR_MASK request_mask;
}tDIS_CB;
-
-
#ifdef __cplusplus
extern "C" {
#endif
#define dis_cb (*dis_cb_ptr)
#endif
-
extern BOOLEAN dis_valid_handle_range(UINT16 handle);
extern UINT8 dis_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value,
BOOLEAN is_long, tGATT_STATUS *p_status);
extern void dis_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
-
#ifdef __cplusplus
}
#endif
LOCAL_MODULE:= bdt
LOCAL_SHARED_LIBRARIES += libcutils \
- libhardware \
- libhardware_legacy
+ libhardware
LOCAL_MULTILIB := 32
--- /dev/null
+#
+# 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.
+#
+
+source_set("udrv") {
+ sources = [
+ "ulinux/uipc.c"
+ ]
+
+ include_dirs = [
+ "include",
+ "uipc",
+ "//",
+ "//audio_a2dp_hw",
+ "//include",
+ "//gki/common",
+ "//stack/include",
+ "//utils/include",
+ ]
+}
*
*****************************************************************************/
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <signal.h>
#include <errno.h>
+#include <fcntl.h>
#include <pthread.h>
-#include <sys/select.h>
-#include <sys/poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/mman.h>
-#include <sys/stat.h>
+#include <sys/poll.h>
#include <sys/prctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
-
-#include "gki.h"
-#include "bt_types.h"
-#include "uipc.h"
-
-#include <cutils/sockets.h>
#include "audio_a2dp_hw.h"
+#include "bt_types.h"
#include "bt_utils.h"
+#include "gki.h"
+#include "osi/include/socket_utils/sockets.h"
+#include "uipc.h"
/*****************************************************************************
** Constants & Macros
BTIF_TRACE_EVENT("create_server_socket %s", name);
- if(socket_local_server_bind(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0)
+ if(osi_socket_local_server_bind(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0)
{
BTIF_TRACE_EVENT("socket failed to create (%s)", strerror(errno));
close(s);
--- /dev/null
+#
+# 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.
+#
+
+static_library("utils") {
+ sources = [
+ "src/bt_utils.c"
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//stack/include",
+ ]
+}
#define LOG_TAG "bt_utils"
-#include <cutils/properties.h>
-#include <cutils/sched_policy.h>
+#include "bt_utils.h"
+
#include <errno.h>
#include <pthread.h>
-#include <sys/resource.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/resource.h>
#include <unistd.h>
+
#include <utils/ThreadDefs.h>
+#include <cutils/sched_policy.h>
+
+// TODO(armansito): cutils/properties.h is only being used to pull-in runtime
+// settings on Android. Remove this conditional include once we have a generic
+// way to obtain system properties.
+#if !defined(OS_GENERIC)
+#include <cutils/properties.h>
+#endif // !defined(OS_GENERIC)
#include "bt_types.h"
-#include "bt_utils.h"
#include "btcore/include/module.h"
#include "osi/include/compat.h"
#include "osi/include/log.h"
return NULL;
}
-const module_t bt_utils_module = {
+EXPORT_SYMBOL const module_t bt_utils_module = {
.name = BT_UTILS_MODULE,
.init = init,
.start_up = NULL,
}
};
-
+// TODO(armansito): Remove this conditional code once there is a generic way
+// to obtain system properties. System properties are only available on
+// Android. Don't do the following check if this is a generic build.
+#if !defined(OS_GENERIC)
/*****************************************************************************
**
** Function check_do_scheduling_group
}
}
}
+#endif // !defined(OS_GENERIC)
/*****************************************************************************
**
pthread_mutex_lock(&gIdxLock);
g_TaskIdx = high_task;
+ // TODO(armansito): Remove this conditional check once we find a solution
+ // for system/core on non-Android platforms.
+#if defined(OS_GENERIC)
+ rc = -1;
+#else // !defined(OS_GENERIC)
pthread_once(&g_DoSchedulingGroupOnce[g_TaskIdx], check_do_scheduling_group);
if (g_DoSchedulingGroup[g_TaskIdx]) {
// set_sched_policy does not support tid == 0
rc = set_sched_policy(tid, SP_AUDIO_SYS);
}
+#endif // defined(OS_GENERIC)
+
g_TaskIDs[high_task] = tid;
pthread_mutex_unlock(&gIdxLock);
if (rc) {
- LOG_WARN("failed to change sched policy, tid %d, err: %d", tid, errno);
+ LOG_WARN(LOG_TAG, "failed to change sched policy, tid %d, err: %d", tid, errno);
}
// always use urgent priority for HCI worker thread until we can adjust
priority = ANDROID_PRIORITY_URGENT_AUDIO;
if (setpriority(PRIO_PROCESS, tid, priority) < 0) {
- LOG_WARN("failed to change priority tid: %d to %d", tid, priority);
+ LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);
}
}
{
if (setpriority(PRIO_PROCESS, tid, priority) < 0)
{
- LOG_WARN("failed to change priority tid: %d to %d", tid, priority);
+ LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);
}
}
}
--- /dev/null
+#
+# 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.
+#
+
+group("vendor-libs") {
+ deps = [
+ "linux:bt-vendor-linux",
+ "test_vendor_lib:test_vendor_lib",
+ ]
+}
--- /dev/null
+#
+# Copyright (C) 2015 Intel Corporation
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(BOARD_HAVE_BLUETOOTH_LINUX), true)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bt_vendor_linux.c
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/../../
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils
+
+LOCAL_MODULE := libbt-vendor
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # BOARD_HAVE_BLUETOOTH_LINUX
--- /dev/null
+#
+# 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.
+#
+
+shared_library("bt-vendor-linux") {
+ sources = [
+ "bt_vendor_linux.c"
+ ]
+
+ include_dirs = [
+ "//"
+ ]
+}
--- /dev/null
+/**********************************************************************
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * 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_vendor"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+#include <poll.h>
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <cutils/properties.h>
+
+#include "hci/include/bt_vendor_lib.h"
+#include "osi/include/log.h"
+
+#define BTPROTO_HCI 1
+#define HCI_CHANNEL_USER 1
+#define HCI_CHANNEL_CONTROL 3
+#define HCI_DEV_NONE 0xffff
+
+#define RFKILL_TYPE_BLUETOOTH 2
+#define RFKILL_OP_CHANGE_ALL 3
+
+#define MGMT_OP_INDEX_LIST 0x0003
+#define MGMT_EV_INDEX_ADDED 0x0004
+#define MGMT_EV_COMMAND_COMP 0x0001
+#define MGMT_EV_SIZE_MAX 1024
+#define MGMT_EV_POLL_TIMEOUT 3000 /* 3000ms */
+
+#define IOCTL_HCIDEVDOWN _IOW('H', 202, int)
+
+struct sockaddr_hci {
+ sa_family_t hci_family;
+ unsigned short hci_dev;
+ unsigned short hci_channel;
+};
+
+struct rfkill_event {
+ uint32_t idx;
+ uint8_t type;
+ uint8_t op;
+ uint8_t soft, hard;
+} __attribute__((packed));
+
+struct mgmt_pkt {
+ uint16_t opcode;
+ uint16_t index;
+ uint16_t len;
+ uint8_t data[MGMT_EV_SIZE_MAX];
+} __attribute__((packed));
+
+struct mgmt_event_read_index {
+ uint16_t cc_opcode;
+ uint8_t status;
+ uint16_t num_intf;
+ uint16_t index[0];
+} __attribute__((packed));
+
+static const bt_vendor_callbacks_t *bt_vendor_callbacks;
+static unsigned char bt_vendor_local_bdaddr[6];
+static int bt_vendor_fd = -1;
+static int hci_interface;
+static int rfkill_en;
+static int bt_hwcfg_en;
+
+static int bt_vendor_init(const bt_vendor_callbacks_t *p_cb,
+ unsigned char *local_bdaddr)
+{
+ char prop_value[PROPERTY_VALUE_MAX];
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ if (p_cb == NULL) {
+ LOG_ERROR(LOG_TAG, "init failed with no user callbacks!");
+ return -1;
+ }
+
+ bt_vendor_callbacks = p_cb;
+
+ memcpy(bt_vendor_local_bdaddr, local_bdaddr,
+ sizeof(bt_vendor_local_bdaddr));
+
+ property_get("bluetooth.interface", prop_value, "0");
+
+ errno = 0;
+ if (memcmp(prop_value, "hci", 3))
+ hci_interface = strtol(prop_value, NULL, 10);
+ else
+ hci_interface = strtol(prop_value + 3, NULL, 10);
+ if (errno)
+ hci_interface = 0;
+
+ LOG_INFO(LOG_TAG, "Using interface hci%d", hci_interface);
+
+ property_get("bluetooth.rfkill", prop_value, "0");
+
+ rfkill_en = atoi(prop_value);
+ if (rfkill_en)
+ LOG_INFO(LOG_TAG, "RFKILL enabled");
+
+ bt_hwcfg_en = property_get("bluetooth.hwcfg",
+ prop_value, NULL) > 0 ? 1 : 0;
+ if (bt_hwcfg_en)
+ LOG_INFO(LOG_TAG, "HWCFG enabled");
+
+ return 0;
+}
+
+static int bt_vendor_hw_cfg(int stop)
+{
+ if (!bt_hwcfg_en)
+ return 0;
+
+ if (stop) {
+ if (property_set("bluetooth.hwcfg", "stop") < 0) {
+ LOG_ERROR(LOG_TAG, "%s cannot stop btcfg service via prop", __func__);
+ return 1;
+ }
+ } else {
+ if (property_set("bluetooth.hwcfg", "start") < 0) {
+ LOG_ERROR(LOG_TAG, "%s cannot start btcfg service via prop", __func__);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int bt_vendor_wait_hcidev(void)
+{
+ struct sockaddr_hci addr;
+ struct pollfd fds[1];
+ struct mgmt_pkt ev;
+ int fd;
+ int ret = 0;
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (fd < 0) {
+ LOG_ERROR(LOG_TAG, "Bluetooth socket error: %s", strerror(errno));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.hci_family = AF_BLUETOOTH;
+ addr.hci_dev = HCI_DEV_NONE;
+ addr.hci_channel = HCI_CHANNEL_CONTROL;
+
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ LOG_ERROR(LOG_TAG, "HCI Channel Control: %s", strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ fds[0].fd = fd;
+ fds[0].events = POLLIN;
+
+ /* Read Controller Index List Command */
+ ev.opcode = MGMT_OP_INDEX_LIST;
+ ev.index = HCI_DEV_NONE;
+ ev.len = 0;
+ if (write(fd, &ev, 6) != 6) {
+ LOG_ERROR(LOG_TAG, "Unable to write mgmt command: %s", strerror(errno));
+ ret = -1;
+ goto end;
+ }
+
+ while (1) {
+ int n = poll(fds, 1, MGMT_EV_POLL_TIMEOUT);
+ if (n == -1) {
+ LOG_ERROR(LOG_TAG, "Poll error: %s", strerror(errno));
+ ret = -1;
+ break;
+ } else if (n == 0) {
+ LOG_ERROR(LOG_TAG, "Timeout, no HCI device detected");
+ ret = -1;
+ break;
+ }
+
+ if (fds[0].revents & POLLIN) {
+ n = read(fd, &ev, sizeof(struct mgmt_pkt));
+ if (n < 0) {
+ LOG_ERROR(LOG_TAG,
+ "Error reading control channel");
+ ret = -1;
+ break;
+ }
+
+ if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
+ goto end;
+ } else if (ev.opcode == MGMT_EV_COMMAND_COMP) {
+ struct mgmt_event_read_index *cc;
+ int i;
+
+ cc = (struct mgmt_event_read_index *)ev.data;
+
+ if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0)
+ continue;
+
+ for (i = 0; i < cc->num_intf; i++) {
+ if (cc->index[i] == hci_interface)
+ goto end;
+ }
+ }
+ }
+ }
+
+end:
+ close(fd);
+ return ret;
+}
+
+static int bt_vendor_open(void *param)
+{
+ int (*fd_array)[] = (int (*)[]) param;
+ int fd;
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (fd < 0) {
+ LOG_ERROR(LOG_TAG, "socket create error %s", strerror(errno));
+ return -1;
+ }
+
+ (*fd_array)[CH_CMD] = fd;
+ (*fd_array)[CH_EVT] = fd;
+ (*fd_array)[CH_ACL_OUT] = fd;
+ (*fd_array)[CH_ACL_IN] = fd;
+
+ bt_vendor_fd = fd;
+
+ LOG_INFO(LOG_TAG, "%s returning %d", __func__, bt_vendor_fd);
+
+ return 1;
+}
+
+static int bt_vendor_close(void *param)
+{
+ (void)(param);
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ if (bt_vendor_fd != -1) {
+ close(bt_vendor_fd);
+ bt_vendor_fd = -1;
+ }
+
+ return 0;
+}
+
+static int bt_vendor_rfkill(int block)
+{
+ struct rfkill_event event;
+ int fd, len;
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ fd = open("/dev/rfkill", O_WRONLY);
+ if (fd < 0) {
+ LOG_ERROR(LOG_TAG, "Unable to open /dev/rfkill");
+ return -1;
+ }
+
+ memset(&event, 0, sizeof(struct rfkill_event));
+ event.op = RFKILL_OP_CHANGE_ALL;
+ event.type = RFKILL_TYPE_BLUETOOTH;
+ event.hard = block;
+ event.soft = block;
+
+ len = write(fd, &event, sizeof(event));
+ if (len < 0) {
+ LOG_ERROR(LOG_TAG, "Failed to change rfkill state");
+ close(fd);
+ return 1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+/* TODO: fw config should thread the device waiting and return immedialty */
+static void bt_vendor_fw_cfg(void)
+{
+ struct sockaddr_hci addr;
+ int fd = bt_vendor_fd;
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ if (fd == -1) {
+ LOG_ERROR(LOG_TAG, "bt_vendor_fd: %s", strerror(EBADF));
+ goto failure;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.hci_family = AF_BLUETOOTH;
+ addr.hci_dev = hci_interface;
+ addr.hci_channel = HCI_CHANNEL_USER;
+
+ if (bt_vendor_wait_hcidev()) {
+ LOG_ERROR(LOG_TAG, "HCI interface (%d) not found", hci_interface);
+ goto failure;
+ }
+
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ LOG_ERROR(LOG_TAG, "socket bind error %s", strerror(errno));
+ goto failure;
+ }
+
+ LOG_INFO(LOG_TAG, "HCI device ready");
+
+ bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+
+ return;
+
+failure:
+ LOG_ERROR(LOG_TAG, "Hardware Config Error");
+ bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+}
+
+static int bt_vendor_op(bt_vendor_opcode_t opcode, void *param)
+{
+ int retval = 0;
+
+ LOG_INFO(LOG_TAG, "%s op %d", __func__, opcode);
+
+ switch (opcode) {
+ case BT_VND_OP_POWER_CTRL:
+ if (!rfkill_en || !param)
+ break;
+
+ if (*((int *)param) == BT_VND_PWR_ON) {
+ retval = bt_vendor_rfkill(0);
+ if (!retval)
+ retval = bt_vendor_hw_cfg(0);
+ } else {
+ retval = bt_vendor_hw_cfg(1);
+ if (!retval)
+ retval = bt_vendor_rfkill(1);
+ }
+
+ break;
+
+ case BT_VND_OP_FW_CFG:
+ bt_vendor_fw_cfg();
+ break;
+
+ case BT_VND_OP_SCO_CFG:
+ bt_vendor_callbacks->scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
+ break;
+
+ case BT_VND_OP_USERIAL_OPEN:
+ retval = bt_vendor_open(param);
+ break;
+
+ case BT_VND_OP_USERIAL_CLOSE:
+ retval = bt_vendor_close(param);
+ break;
+
+ case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
+ *((uint32_t *)param) = 3000;
+ retval = 0;
+ break;
+
+ case BT_VND_OP_LPM_SET_MODE:
+ bt_vendor_callbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS);
+ break;
+
+ case BT_VND_OP_LPM_WAKE_SET_STATE:
+ break;
+
+ case BT_VND_OP_SET_AUDIO_STATE:
+ bt_vendor_callbacks->audio_state_cb(BT_VND_OP_RESULT_SUCCESS);
+ break;
+
+ case BT_VND_OP_EPILOG:
+ bt_vendor_callbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
+ break;
+ }
+
+ LOG_INFO(LOG_TAG, "%s op %d retval %d", __func__, opcode, retval);
+
+ return retval;
+}
+
+static void bt_vendor_cleanup(void)
+{
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ bt_vendor_callbacks = NULL;
+}
+
+const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
+ sizeof(bt_vendor_interface_t),
+ bt_vendor_init,
+ bt_vendor_op,
+ bt_vendor_cleanup,
+};
--- /dev/null
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+BT_DIR := $(TOP_DIR)system/bt
+
+LOCAL_SRC_FILES := \
+ src/bt_vendor.cc \
+ src/command_packet.cc \
+ src/dual_mode_controller.cc \
+ src/event_packet.cc \
+ src/hci_transport.cc \
+ src/packet.cc \
+ src/packet_stream.cc \
+ src/test_channel_transport.cc \
+ src/vendor_manager.cc
+
+# We pull in gtest because base/files/file_util.h, which is used to read the
+# controller properties file, needs gtest/gtest_prod.h.
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
+ $(BT_DIR) \
+ $(BT_DIR)/hci/include \
+ $(BT_DIR)/osi/include \
+ $(BT_DIR)/stack/include \
+ $(BT_DIR)/third_party/gtest/include
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libchrome
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CFLAGS += -std=c++11
+LOCAL_MODULE := test-vendor
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+include $(BUILD_SHARED_LIBRARY)
+
+ifeq ($(HOST_OS), linux)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ src/command_packet.cc \
+ src/event_packet.cc \
+ src/hci_transport.cc \
+ src/packet.cc \
+ src/packet_stream.cc \
+ test/hci_transport_unittest.cc \
+ test/packet_stream_unittest.cc
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
+ $(BT_DIR) \
+ $(BT_DIR)/hci/include \
+ $(BT_DIR)/osi/include \
+ $(BT_DIR)/stack/include
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libchrome-host
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CFLAGS += -std=c++11
+LOCAL_MODULE := test-vendor_test_host
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_HOST_NATIVE_TEST)
+endif
--- /dev/null
+shared_library("test_vendor_lib") {
+ sources = [
+ "src/bt_vendor.cc",
+ "src/command_packet.cc",
+ "src/dual_mode_controller.cc",
+ "src/event_packet.cc",
+ "src/hci_transport.cc",
+ "src/packet.cc",
+ "src/packet_stream.cc",
+ "src/test_channel_transport.cc",
+ "src/vendor_manager.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ # TODO(dennischeng): Ideally we should need to have the lines below for
+ # indirect includes.
+ "//osi/include",
+ "//stack/include",
+ ]
+}
+
+executable("test_vendor_lib_test") {
+ testonly = true
+ sources = [
+ "src/command_packet.cc",
+ "src/event_packet.cc",
+ "src/packet.cc",
+ "src/packet_stream.cc",
+ "test/hci_transport_unittest.cc",
+ "test/packet_stream_unittest.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//btcore/include",
+ "//hci/include",
+ "//osi/include",
+ "//stack/include",
+ ]
+
+ deps = [
+ "//third_party/gtest:gtest_main",
+ "//third_party/libchrome:base",
+ "//vendor_libs/test_vendor_lib",
+ ]
+
+ libs = [
+ "-lpthread",
+ "-lrt",
+ "-ldl",
+ ]
+}
--- /dev/null
+{
+ "AclDataPacketSize": "1024",
+ "ScoDataPacketSize": "255",
+ "NumAclDataPackets": "10",
+ "NumScoDataPackets": "10",
+ "Version": "4",
+ "Revision": "0",
+ "LmpPalVersion": "0",
+ "ManufacturerName": "0",
+ "LmpPalSubversion": "0",
+ "MaximumPageNumber": "0",
+ "BdAddress": "123456"
+}
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 <cstdint>
+#include <vector>
+
+#include "base/macros.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+namespace test_vendor_lib {
+
+// The following is specified in the Bluetooth Core Specification Version 4.2,
+// Volume 2, Part E, Section 5.4.1 (page 470). Command Packets begin with a 3
+// octet header formatted as follows:
+// - Opcode: 2 octets
+// - Opcode Group Field (OGF): Upper bits 10-15
+// - Opcode Command Field (OCF): Lower bits 0-9
+// - Payload size (in octets): 1 octet
+// The header is followed by the payload, which contains command specific
+// parameters and has a maximum size of 255 octets. Valid command opcodes are
+// defined in stack/include/hcidefs.h. The OGF ranges from 0x00 to 0x3F, with
+// 0x3F reserved for vendor-specific debug functions. The OCF ranges from
+// 0x0000 to 0x03FF. Note that the payload size is the size in octets of the
+// command parameters and not the number of parameters. Finally, although the
+// parameters contained in the payload are command specific (including the size
+// and number of parameters), each parameter will be an integer number of octets
+// in size.
+class CommandPacket : public Packet {
+ public:
+ CommandPacket();
+
+ virtual ~CommandPacket() override = default;
+
+ // Returns the command opcode as defined in stack/include/hcidefs.h.
+ // See the Bluetooth Core Specification Version 4.2, Volume 2, Part E,
+ // Section 7 for more information about each HCI commands and for a listing
+ // of their specific opcodes/OGF and OCF values.
+ uint16_t GetOpcode() const;
+
+ // Returns the 6 bit opcode group field that specifies the general category of
+ // the command. The OGF can be one of seven values:
+ // - 0x01: Link control commands
+ // - 0x02: Link policy commands
+ // - 0x03: Controller and baseband commands
+ // - 0x04: Informational parameters commands
+ // - 0x05: Status parameters commands
+ // - 0x06: Testing commands
+ // - 0x08: Low energy controller commands
+ // The upper 2 bits will be zero filled.
+ uint8_t GetOGF() const;
+
+ // Returns the 10 bit opcode command field that specifies an exact command
+ // within an opcode group field. The upper 6 bits will be zero filled.
+ uint16_t GetOCF() const;
+
+ // Size in octets of a command packet header, which consists of a 2 octet
+ // opcode and a 1 octet payload size.
+ static const size_t kCommandHeaderSize = 3;
+
+ private:
+ // Disallow any copies of the singleton to be made.
+ DISALLOW_COPY_AND_ASSIGN(CommandPacket);
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+#include <unordered_map>
+
+#include "base/json/json_value_converter.h"
+#include "base/time/time.h"
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+#include "vendor_libs/test_vendor_lib/include/test_channel_transport.h"
+
+namespace test_vendor_lib {
+
+// Emulates a dual mode BR/EDR + LE controller by maintaining the link layer
+// state machine detailed in the Bluetooth Core Specification Version 4.2,
+// Volume 6, Part B, Section 1.1 (page 30). Provides methods corresponding to
+// commands sent by the HCI. These methods will be registered as callbacks from
+// a controller instance with the HciHandler. To implement a new Bluetooth
+// command, simply add the method declaration below, with return type void and a
+// single const std::vector<uint8_t>& argument. After implementing the
+// method, simply register it with the HciHandler using the SET_HANDLER macro in
+// the controller's default constructor. Be sure to name your method after the
+// corresponding Bluetooth command in the Core Specification with the prefix
+// "Hci" to distinguish it as a controller command.
+class DualModeController {
+ public:
+ class Properties {
+ public:
+ // TODO(dennischeng): Add default initialization and use that to instantiate
+ // a default configured controller if the config file is invalid or not
+ // provided.
+ Properties(const std::string& file_name);
+
+ // Aggregates and returns the result for the Read Local Extended Features
+ // command. This result contains the |maximum_page_number_| property (among
+ // other things not in the Properties object). See the Bluetooth Core
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.4 (page 792).
+ const std::vector<uint8_t> GetBdAddress();
+
+ // Aggregates and returns the result for the Read Buffer Size command. This
+ // result consists of the |acl_data_packet_size_|, |sco_data_packet_size_|,
+ // |num_acl_data_packets_|, and |num_sco_data_packets_| properties. See the
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
+ // (page 794).
+ const std::vector<uint8_t> GetBufferSize();
+
+ // Returns the result for the Read BD_ADDR command. This result is the
+ // |bd_address_| property. See the Bluetooth Core Specification Version
+ // 4.2, Volume 2, Part E, Section 7.4.6 (page 796).
+ const std::vector<uint8_t> GetLocalExtendedFeatures(uint8_t page_number);
+
+ // Returns the result for the Read Local Name command. See the Bluetooth
+ // Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
+ // (page 664).
+ const std::vector<uint8_t> GetLocalName();
+
+ // Returns the result for the Read Local Supported Commands command. See the
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
+ // (page 790).
+ const std::vector<uint8_t> GetLocalSupportedCommands();
+
+ // Aggregates and returns the Read Local Version Information result. This
+ // consists of the |version_|, |revision_|, |lmp_pal_version_|,
+ // |manufacturer_name_|, and |lmp_pal_subversion_|. See the Bluetooth Core
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.1 (page 788).
+ const std::vector<uint8_t> GetLocalVersionInformation();
+
+ static void RegisterJSONConverter(
+ base::JSONValueConverter<Properties>* converter);
+
+ private:
+ uint16_t acl_data_packet_size_;
+ uint8_t sco_data_packet_size_;
+ uint16_t num_acl_data_packets_;
+ uint16_t num_sco_data_packets_;
+ uint8_t version_;
+ uint16_t revision_;
+ uint8_t lmp_pal_version_;
+ uint16_t manufacturer_name_;
+ uint16_t lmp_pal_subversion_;
+ uint8_t maximum_page_number_;
+ uint8_t local_supported_commands_size_;
+ uint8_t local_name_size_;
+ std::vector<uint8_t> bd_address_;
+ };
+
+ // Sets all of the methods to be used as callbacks in the HciHandler.
+ DualModeController();
+
+ ~DualModeController() = default;
+
+ // Preprocesses the command, primarily checking testh channel hooks. If
+ // possible, dispatches the corresponding controller method corresponding to
+ // carry out the command.
+ void HandleCommand(std::unique_ptr<CommandPacket> command_packet);
+
+ // Dispatches the test channel action corresponding to the command specified
+ // by |name|.
+ void HandleTestChannelCommand(const std::string& name,
+ const std::vector<std::string>& args);
+
+ // Sets the controller Handle* methods as callbacks for the transport to call
+ // when data is received.
+ void RegisterHandlersWithHciTransport(HciTransport& transport);
+
+ // Sets the test channel handler with the transport dedicated to test channel
+ // communications.
+ void RegisterHandlersWithTestChannelTransport(
+ TestChannelTransport& transport);
+
+ // Sets the callback to be used for sending events back to the HCI.
+ // TODO(dennischeng): Once PostDelayedTask works, get rid of this and only use
+ // |RegisterDelayedEventChannel|.
+ void RegisterEventChannel(
+ std::function<void(std::unique_ptr<EventPacket>)> send_event);
+
+ void RegisterDelayedEventChannel(
+ std::function<void(std::unique_ptr<EventPacket>, base::TimeDelta)>
+ send_event);
+
+ // Controller commands. For error codes, see the Bluetooth Core Specification,
+ // Version 4.2, Volume 2, Part D (page 370).
+
+ // OGF: 0x0003
+ // OCF: 0x0003
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.2
+ void HciReset(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OGF: 0x0005
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.5
+ void HciReadBufferSize(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0033
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.39
+ void HciHostBufferSize(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OCF: 0x0001
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.1
+ void HciReadLocalVersionInformation(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OCF: 0x0009
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.6
+ void HciReadBdAddr(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OCF: 0x0002
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.2
+ void HciReadLocalSupportedCommands(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OCF: 0x0004
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.4
+ void HciReadLocalExtendedFeatures(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0056
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.59
+ void HciWriteSimplePairingMode(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x006D
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.79
+ void HciWriteLeHostSupport(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0001
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.1
+ void HciSetEventMask(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0045
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.50
+ void HciWriteInquiryMode(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0047
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.52
+ void HciWritePageScanType(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0043
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.48
+ void HciWriteInquiryScanType(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0024
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.26
+ void HciWriteClassOfDevice(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0018
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.16
+ void HciWritePageTimeout(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0002
+ // OCF: 0x000F
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.2.12
+ void HciWriteDefaultLinkPolicySettings(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0014
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.12
+ void HciReadLocalName(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0013
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.11
+ void HciWriteLocalName(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0052
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.56
+ void HciWriteExtendedInquiryResponse(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0026
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.28
+ void HciWriteVoiceSetting(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x003A
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.45
+ void HciWriteCurrentIacLap(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x001E
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.22
+ void HciWriteInquiryScanActivity(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x001A
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.18
+ void HciWriteScanEnable(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0005
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.3
+ void HciSetEventFilter(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0001
+ // OCF: 0x0001
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1.1
+ void HciInquiry(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0001
+ // OCF: 0x0002
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1.2
+ void HciInquiryCancel(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0012
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.10
+ void HciDeleteStoredLinkKey(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0001
+ // OCF: 0x0019
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1.19
+ void HciRemoteNameRequest(const std::vector<uint8_t>& args);
+
+ // Test Channel commands:
+
+ // Clears all test channel modifications.
+ void TestChannelClear(const std::vector<std::string>& args);
+
+ // Sets the response delay for events to 0.
+ void TestChannelClearEventDelay(const std::vector<std::string>& args);
+
+ // Discovers a fake device.
+ void TestChannelDiscover(const std::vector<std::string>& args);
+
+ // Causes events to be sent after a delay.
+ void TestChannelSetEventDelay(const std::vector<std::string>& args);
+
+ // Causes all future HCI commands to timeout.
+ void TestChannelTimeoutAll(const std::vector<std::string>& args);
+
+ private:
+ // Current link layer state of the controller.
+ enum State {
+ kStandby, // Not receiving/transmitting any packets from/to other devices.
+ kInquiry, // The controller is discovering other nearby devices.
+ };
+
+ enum TestChannelState {
+ kNone, // The controller is running normally.
+ kTimeoutAll, // All commands should time out, i.e. send no response.
+ kDelayedResponse, // Event responses are sent after a delay.
+ };
+
+ // Creates a command complete event and sends it back to the HCI.
+ void SendCommandComplete(uint16_t command_opcode,
+ const std::vector<uint8_t>& return_parameters) const;
+
+ // Sends a command complete event with no return parameters. This event is
+ // typically sent for commands that can be completed immediately.
+ void SendCommandCompleteSuccess(uint16_t command_opcode) const;
+
+ // Creates a command status event and sends it back to the HCI.
+ void SendCommandStatus(uint8_t status, uint16_t command_opcode) const;
+
+ // Sends a command status event with default event parameters.
+ void SendCommandStatusSuccess(uint16_t command_opcode) const;
+
+ // Sends an inquiry response for a fake device.
+ void SendInquiryResult() const;
+
+ // Sends an extended inquiry response for a fake device.
+ void SendExtendedInquiryResult(const std::string& name,
+ const std::string& address) const;
+
+ void SetEventDelay(int64_t delay);
+
+ // Callback provided to send events from the controller back to the HCI.
+ std::function<void(std::unique_ptr<EventPacket>)> send_event_;
+
+ std::function<void(std::unique_ptr<EventPacket>, base::TimeDelta)>
+ send_delayed_event_;
+
+ // Maintains the commands to be registered and used in the HciHandler object.
+ // Keys are command opcodes and values are the callbacks to handle each
+ // command.
+ std::unordered_map<uint16_t, std::function<void(const std::vector<uint8_t>&)>>
+ active_hci_commands_;
+
+ std::unordered_map<std::string,
+ std::function<void(const std::vector<std::string>&)>>
+ active_test_channel_commands_;
+
+ // Specifies the format of Inquiry Result events to be returned during the
+ // Inquiry command.
+ // 0x00: Standard Inquiry Result event format (default).
+ // 0x01: Inquiry Result format with RSSI.
+ // 0x02 Inquiry Result with RSSI format or Extended Inquiry Result format.
+ // 0x03-0xFF: Reserved.
+ uint8_t inquiry_mode_;
+
+ State state_;
+
+ Properties properties_;
+
+ TestChannelState test_channel_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(DualModeController);
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 <cstdint>
+#include <memory>
+#include <vector>
+
+#include "base/logging.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+namespace test_vendor_lib {
+
+// The following is specified in the Bluetooth Core Specification Version 4.2,
+// Volume 2, Part E, Section 5.4.4 (page 477). Event Packets begin with a 2
+// octet header formatted as follows:
+// - Event code: 1 octet
+// - Payload size (in octets): 1 octet
+// The header is followed by the payload, which contains event specific
+// parameters and has a maximum size of 255 octets. Valid event codes are
+// listed in stack/include/hcidefs.h. They can range from 0x00 to 0xFF, with
+// 0xFF reserved for vendor specific debug events. Note the payload size
+// describes the total size of the event parameters and not the number of
+// parameters. The event parameters contained in the payload will be an integer
+// number of octets in size. Each flavor of event packet is created via a static
+// factory function that takes the event type-specific parameters and returns an
+// initialized event packet from that data.
+class EventPacket : public Packet {
+ public:
+ virtual ~EventPacket() override = default;
+
+ uint8_t GetEventCode() const;
+
+ // Static functions for creating event packets:
+
+ // Creates and returns a command complete event packet. See the Bluetooth
+ // Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14 (page 861)
+ // for more information about the command complete event.
+ // Event Parameters:
+ // |num_hci_command_packets|
+ // Indicates the number of HCI command packets the host can send to the
+ // controller. If |num_hci_command_packets| is 0, the controller would
+ // like to stop receiving commands from the host (to indicate
+ // readiness again, the controller sends a command complete event with
+ // |command_opcode| to 0x0000 (no op) and |num_hci_command_packets| > 1).
+ // |command_opcode|
+ // The opcode of the command that caused this event.
+ // |return_parameters|
+ // Contains any event specific parameters that should
+ // be sent to the host.
+ static std::unique_ptr<EventPacket> CreateCommandCompleteEvent(
+ uint8_t num_hci_command_packets, uint16_t command_opcode,
+ const std::vector<uint8_t>& event_return_parameters);
+
+ // Creates and returns a command complete event packet. See the Bluetooth
+ // Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15 (page 862)
+ // for more information about the command complete event.
+ // Event Parameters:
+ // Status
+ // 0x00: Command currently in pending.
+ // 0x01-0xFF: Command failed.
+ // |num_hci_command_packets|
+ // Indicates the number of HCI command packets the host can send to the
+ // controller. If |num_hci_command_packets| is 0, the controller would
+ // like to stop receiving commands from the host (to indicate
+ // readiness again, the controller sends a command complete event with
+ // |command_opcode| to 0x0000 (no op) and |num_hci_command_packets| > 1).
+ // |command_opcode|
+ // The opcode of the command that caused this event.
+ static std::unique_ptr<EventPacket> CreateCommandStatusEvent(
+ uint8_t status, uint8_t num_hci_command_packets, uint16_t command_opcode);
+
+ // Creates and returns an inquiry result event packet. See the Bluetooth
+ // Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2 (page 844)
+ // for more information about the command complete event.
+ // Event Parameters:
+ // Num Responses (1 octet)
+ // 0xXX: Number of responses from the inquiry.
+ // Bd Addresses (6 octets * Num Responses)
+ // 0xXXXXXXXXXXX: Bd Address for each device which responded.
+ // Page Scan Repetition Mode (1 octet * Num Responses)
+ // 0x00: R0
+ // 0x01: R1
+ // 0x02: R2
+ // 0x03-0xFF: Reserved.
+ // Reserved 1 (1 octet * Num Responses)
+ // Originally Page Scan Period Mode parameter. No longer in use.
+ // Reserved 2 (1 octet * Num Responses)
+ // Originally Page Scan Mode parameter. No longer in use.
+ // Class of Device (3 octet * Num Responses)
+ // 0xXXXXXX: Class of device.
+ // Clock Offset (2 octet * Num Responses)
+ // Bits 14-0: Bits 16-2 of CLKNslave-CLK.
+ // Bits 15: Reserved.
+ static std::unique_ptr<EventPacket> CreateInquiryResultEvent(
+ uint8_t num_responses, const std::vector<uint8_t>& bd_addresses,
+ const std::vector<uint8_t>& page_scan_repetition_mode,
+ const std::vector<uint8_t>& page_scan_period_mode,
+ const std::vector<uint8_t>& page_scan_mode,
+ const std::vector<uint8_t>& class_of_device,
+ const std::vector<uint8_t>& clock_offset);
+
+ // Creates and returns an inquiry result event packet. See the Bluetooth
+ // Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38 (page 896)
+ // for more information about the command complete event.
+ // Event Parameters:
+ // Num Responses (1 octet)
+ // 0x01: Always contains a single response.
+ // Bd Addresses (6 octets * Num Responses)
+ // 0xXXXXXXXXXXX: Bd Address for each device which responded.
+ // Page Scan Repetition Mode (1 octet * Num Responses)
+ // 0x00: R0
+ // 0x01: R1
+ // 0x02: R2
+ // 0x03-0xFF: Reserved.
+ // Reserved 1 (1 octet * Num Responses)
+ // Originally Page Scan Period Mode parameter. No longer in use.
+ // Class of Device (3 octet * Num Responses)
+ // 0xXXXXXX: Class of device.
+ // Clock Offset (2 octet * Num Responses)
+ // Bits 14-0: Bits 16-2 of CLKNslave-CLK.
+ // Bits 15: Reserved.
+ // RSSI (1 octet)
+ // 0xXX: Ranges from -127 to +20. Units are dBm.
+ // Extended Inquiry Response (240 octets)
+ // Defined in Volumne 2, Part C, Section 8. Also see the Supplement to the
+ // Bluetooth Core Specificiation for data type definitions and formats.
+ static std::unique_ptr<EventPacket> CreateExtendedInquiryResultEvent(
+ const std::vector<uint8_t>& bd_address,
+ const std::vector<uint8_t>& page_scan_repetition_mode,
+ const std::vector<uint8_t>& page_scan_period_mode,
+ const std::vector<uint8_t>& class_of_device,
+ const std::vector<uint8_t>& clock_offset,
+ const std::vector<uint8_t>& rssi,
+ const std::vector<uint8_t>& extended_inquiry_response);
+
+ // Size in octets of a data packet header, which consists of a 1 octet
+ // event code and a 1 octet payload size.
+ static const size_t kEventHeaderSize = 2;
+
+ private:
+ // Takes in the event parameters in |payload|. These parameters vary by event
+ // and are detailed in the Bluetooth Core Specification.
+ EventPacket(uint8_t event_code, const std::vector<uint8_t>& payload);
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 <functional>
+#include <memory>
+#include <list>
+
+extern "C" {
+#include <sys/epoll.h>
+} // extern "C"
+
+#include "base/files/scoped_file.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet_stream.h"
+
+namespace test_vendor_lib {
+
+// Manages communication channel between HCI and the controller by providing the
+// socketing mechanisms for reading/writing between the HCI and the controller.
+class HciTransport : public base::MessageLoopForIO::Watcher {
+ public:
+ HciTransport();
+
+ virtual ~HciTransport() = default;
+
+ void CloseHciFd();
+
+ void CloseVendorFd();
+
+ int GetHciFd() const;
+
+ int GetVendorFd() const;
+
+ // Creates the underlying socketpair to be used as a communication channel
+ // between the HCI and the vendor library/controller. Returns false if an
+ // error occurs.
+ bool SetUp();
+
+ // Sets the callback that is run when command packets are received.
+ void RegisterCommandHandler(
+ std::function<void(std::unique_ptr<CommandPacket>)> callback);
+
+ // Posts the event onto |outbound_events_| to be written sometime in the
+ // future when the vendor file descriptor is ready for writing.
+ void PostEventResponse(std::unique_ptr<EventPacket> event);
+
+ // Posts the event onto |outbound_events_| after |delay| ms. A call to
+ // |PostEventResponse| with |delay| 0 is equivalent to a call to |PostEvent|.
+ void PostDelayedEventResponse(std::unique_ptr<EventPacket> event,
+ base::TimeDelta delay);
+
+ private:
+ // Wrapper class for sending events on a delay. The TimeStampedEvent object
+ // takes ownership of a given event packet.
+ class TimeStampedEvent {
+ public:
+ TimeStampedEvent(std::unique_ptr<EventPacket> event, base::TimeDelta delay);
+
+ // Using this constructor is equivalent to calling the 2-argument
+ // constructor with a |delay| of 0. It is used to generate event responses
+ // with no delay.
+ TimeStampedEvent(std::unique_ptr<EventPacket> event);
+
+ const base::TimeTicks& GetTimeStamp() const;
+
+ const EventPacket& GetEvent();
+
+ private:
+ std::shared_ptr<EventPacket> event_;
+
+ // The time associated with the event, indicating the earliest time at which
+ // |event_| will be sent.
+ base::TimeTicks time_stamp_;
+ };
+
+ // base::MessageLoopForIO::Watcher overrides:
+ void OnFileCanReadWithoutBlocking(int fd) override;
+
+ void OnFileCanWriteWithoutBlocking(int fd) override;
+
+ // Reads in a command packet and calls the command ready callback,
+ // |command_handler_|, passing ownership of the command packet to the handler.
+ void ReceiveReadyCommand() const;
+
+ void AddEventToOutboundEvents(std::unique_ptr<TimeStampedEvent> event);
+
+ // Write queue for sending events to the HCI. Event packets are removed from
+ // the queue and written when write-readiness is signalled by the message
+ // loop. After being written, the event packets are destructed.
+ std::list<std::unique_ptr<TimeStampedEvent>> outbound_events_;
+
+ // Callback executed in ReceiveReadyCommand() to pass the incoming command
+ // over to the handler for further processing.
+ std::function<void(std::unique_ptr<CommandPacket>)> command_handler_;
+
+ // For performing packet-based IO.
+ PacketStream packet_stream_;
+
+ // The two ends of the socketpair. |hci_fd_| is handed back to the HCI in
+ // bt_vendor.cc and |vendor_fd_| is used by |packet_stream_| to receive/send
+ // data from/to the HCI. Both file descriptors are owned and managed by the
+ // transport object, although |hci_fd_| can be closed by the HCI in
+ // TestVendorOp().
+ std::unique_ptr<base::ScopedFD> hci_fd_;
+ std::unique_ptr<base::ScopedFD> vendor_fd_;
+
+ // This should remain the last member so it'll be destroyed and invalidate
+ // its weak pointers before any other members are destroyed.
+ base::WeakPtrFactory<HciTransport> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(HciTransport);
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 <cstdint>
+#include <vector>
+
+extern "C" {
+#include "hci/include/hci_hal.h"
+} // extern "C"
+
+namespace test_vendor_lib {
+
+// Abstract base class that is subclassed to provide type-specifc accessors on
+// data. Manages said data's memory and guarantees the data's persistence for IO
+// operations.
+class Packet {
+ public:
+ virtual ~Packet() = default;
+
+ // Returns the size in octets of the entire packet, which consists of the type
+ // octet, the header, and the payload.
+ size_t GetPacketSize() const;
+
+ const std::vector<uint8_t>& GetPayload() const;
+
+ uint8_t GetPayloadSize() const;
+
+ const std::vector<uint8_t>& GetHeader() const;
+
+ uint8_t GetHeaderSize() const;
+
+ serial_data_type_t GetType() const;
+
+ // Validates the packet by checking that the payload size in the header is
+ // accurate. If the size is not valid, returns false. Otherwise, the data in
+ // |header| and |payload| is copied into |header_| and |payload_|
+ // respectively. If an error occurs while the data is being copied, the
+ // contents of |header| and |payload| are guaranteed to be preserved. The
+ // packet object will assume ownership of the copied data for its entire
+ // lifetime.
+ bool Encode(const std::vector<uint8_t>& header,
+ const std::vector<uint8_t>& payload);
+
+ protected:
+ // Constructs an empty packet of type |type|. A call to Encode() shall be made
+ // to check and fill in the packet's data.
+ Packet(serial_data_type_t type);
+
+ private:
+ // Underlying containers for storing the actual packet, broken down into the
+ // packet header and the packet payload. Data is copied into the vectors
+ // during the constructor and becomes accessible (read only) to children
+ // through GetHeader() and GetPayload().
+ std::vector<uint8_t> header_;
+
+ std::vector<uint8_t> payload_;
+
+ // The packet type is one of DATA_TYPE_ACL, DATA_TYPE_COMMAND,
+ // DATA_TYPE_EVENT, or DATA_TYPE_SCO.
+ serial_data_type_t type_;
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 <cstdint>
+#include <vector>
+#include <memory>
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+namespace test_vendor_lib {
+
+// Provides abstractions for IO with Packet objects. Used to receive commands
+// and data from the HCI and to send controller events back to the host.
+class PacketStream {
+ public:
+ PacketStream() = default;
+
+ virtual ~PacketStream() = default;
+
+ // Reads a command packet from the file descriptor at |fd| and returns the
+ // packet back to the caller, along with the responsibility of managing the
+ // packet.
+ std::unique_ptr<CommandPacket> ReceiveCommand(int fd) const;
+
+ // Reads a single octet from |fd| and interprets it as a packet type octet.
+ // Validates the type octet for correctness.
+ serial_data_type_t ReceivePacketType(int fd) const;
+
+ // Sends an event to file descriptor |fd|. The ownership of the event is left
+ // with the caller.
+ bool SendEvent(const EventPacket& event, int fd) const;
+
+ private:
+ // Checks if |type| is in the valid range from DATA_TYPE_COMMAND to
+ // DATA_TYPE_SCO.
+ bool ValidateTypeOctet(serial_data_type_t type) const;
+
+ // Attempts to receive |num_octets_to_receive| into |destination| from |fd|,
+ // returning false if an error occurs.
+ bool ReceiveAll(std::vector<uint8_t>& destination,
+ size_t num_octets_to_receive, int fd) const;
+
+ // Attempts to send |num_octets_to_send| from |source| to |fd|, returning
+ // false if an error occurs.
+ bool SendAll(const std::vector<uint8_t>& source, size_t num_octets_to_send,
+ int fd) const;
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 <string>
+#include <memory>
+
+#include "base/files/scoped_file.h"
+#include "base/message_loop/message_loop.h"
+
+namespace test_vendor_lib {
+
+// Manages communications between test channel and the controller. Mirrors the
+// HciTransport for the test channel.
+class TestChannelTransport : public base::MessageLoopForIO::Watcher {
+ public:
+ TestChannelTransport(bool enabled, int port);
+
+ ~TestChannelTransport() = default;
+
+ // Waits for a connection request from the test channel program and
+ // allocates the file descriptor to watch for run-time parameters at. This
+ // file descriptor gets stored in |fd_|.
+ bool SetUp();
+
+ int GetFd();
+
+ // Because it imposes a different flow of work, the test channel must be
+ // actively enabled to be used. |enabled_| is set by the vendor manager.
+ bool IsEnabled();
+
+ // Turns the test channel off for use in circumstances where an error occurs
+ // and leaving the channel on would crash Bluetooth (e.g. if the test channel
+ // is unable to bind to its socket, Bluetooth should still start without the
+ // channel enabled).
+ void Disable();
+
+ // Sets the callback that fires when data is read in
+ // |OnFileCanReadWithoutBlocking|.
+ void RegisterCommandHandler(
+ std::function<void(const std::string&, const std::vector<std::string>&)>
+ callback);
+
+ private:
+ // base::MessageLoopForIO::Watcher overrides:
+ void OnFileCanReadWithoutBlocking(int fd) override;
+
+ void OnFileCanWriteWithoutBlocking(int fd) override;
+
+ std::function<void(const std::string&, const std::vector<std::string>&)>
+ command_handler_;
+
+ // File descriptor to watch for test hook data.
+ std::unique_ptr<base::ScopedFD> fd_;
+
+ // TODO(dennischeng): Get port and enabled flag from a config file.
+ int port_;
+ bool enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestChannelTransport);
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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.
+//
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "hci/include/bt_vendor_lib.h"
+#include "vendor_libs/test_vendor_lib/include/dual_mode_controller.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+#include "vendor_libs/test_vendor_lib/include/test_channel_transport.h"
+
+#include <memory>
+
+namespace test_vendor_lib {
+
+// Contains the three core objects that make up the test vendor library: the
+// HciTransport for communication, the HciHandler for processing commands, and
+// the Controller for actual command implementations. The VendorManager shall
+// operate as a global singleton and be used in bt_vendor.cc to perform vendor
+// specific operations, via |vendor_callbacks_|, and to provide access to the
+// test controller by setting up a message loop (on another thread) that the HCI
+// will talk to and controller methods will execute on.
+class VendorManager {
+ public:
+ // Functions that operate on the global manager instance. Initialize()
+ // is called by the vendor library's TestVendorInitialize() function to create
+ // the global manager and must be called before Get() and CleanUp().
+ // CleanUp() should be called when a call to TestVendorCleanUp() is made
+ // since the global manager should live throughout the entire time the test
+ // vendor library is in use.
+ static void CleanUp();
+
+ static VendorManager* Get();
+
+ static void Initialize();
+
+ void CloseHciFd();
+
+ int GetHciFd() const;
+
+ const bt_vendor_callbacks_t& GetVendorCallbacks() const;
+
+ // Stores a copy of the vendor specific configuration callbacks passed into
+ // the vendor library from the HCI in TestVendorInit().
+ void SetVendorCallbacks(const bt_vendor_callbacks_t& callbacks);
+
+ // Returns true if |thread_| is able to be started and the
+ // StartingWatchingOnThread() task has been posted to the task runner.
+ bool Run();
+
+ private:
+ VendorManager();
+
+ ~VendorManager() = default;
+
+ // Posts a callback to |thread_|'s task runner. Equivalent to calling
+ // |PostDelayedTask| with a delay of 0.
+ bool PostTask(const base::Closure& task);
+
+ // Posts a callback to be run after |delay| ms (or longer) have passed.
+ bool PostDelayedTask(const base::Closure& task, base::TimeDelta delay);
+
+ // Starts watching for incoming data from the HCI and the test hook.
+ void StartWatchingOnThread();
+
+ // Creates the HCI's communication channel and overrides IO callbacks to
+ // receive and send packets.
+ HciTransport transport_;
+
+ // The controller object that provides implementations of Bluetooth commands.
+ DualModeController controller_;
+
+ // The two test channel objects that perform functions corresponding to the
+ // HciTransport and HciHandler.
+ TestChannelTransport test_channel_transport_;
+
+ // Configuration callbacks provided by the HCI for use in TestVendorOp().
+ bt_vendor_callbacks_t vendor_callbacks_;
+
+ // True if the underlying message loop (in |thread_|) is running.
+ bool running_;
+
+ // Dedicated thread for managing the message loop to receive and send packets
+ // from the HCI and to receive additional parameters from the test hook file
+ // descriptor.
+ base::Thread thread_;
+
+ // Used to handle further watching of the vendor's/test channel's file
+ // descriptor after WatchFileDescriptor() is called.
+ base::MessageLoopForIO::FileDescriptorWatcher hci_watcher_;
+
+ // Used to handle further watching of the test channel's file descriptor after
+ // WatchFileDescriptor() is called.
+ base::MessageLoopForIO::FileDescriptorWatcher test_channel_watcher_;
+
+ // This should remain the last member so it'll be destroyed and invalidate
+ // its weak pointers before any other members are destroyed.
+ base::WeakPtrFactory<VendorManager> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(VendorManager);
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+#!/bin/bash
+
+#
+# Copyright 2015 The Android Open Source Project
+#
+# 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.
+#
+
+# Builds and pushes the test vendor library to a connected device and starts
+# logcat with project-specific tag filters. If the --test-channel flag is set,
+# logcat is started in a separate process and the test channel is run in the
+# current shell. The kTestChannelEnabled flag must be set in the vendor manager
+# if the test channel is to be used. Also ensure that 'lunch' has been run for
+# the appropriate device.
+
+if [[ "$#" -ne 2 && "$#" -ne 4 ]]; then
+ echo "Usage:"
+ echo "./build_and_run.sh [/path/to/aosp] [device_name] or"
+ echo "./build_and_run.sh [/path/to/aosp] [device_name] --test-channel [port]"
+ exit 1
+fi
+
+# Exit the script if any command fails.
+set -e
+
+# The home directory for AOSP.
+AOSP_ABS=$1
+# The name of the device to build for.
+DEVICE=$2
+
+# The location of Bluetooth within AOSP.
+BT_REL=/system/bt
+BT_ABS=${AOSP_ABS}${BT_REL}
+
+# The location of the test vendor library.
+TEST_VENDOR_LIB_REL=/vendor_libs/test_vendor_lib
+TEST_VENDOR_LIB_ABS=${BT_ABS}${TEST_VENDOR_LIB_REL}
+
+DEVICE_TARGET_REL=/out/target/product
+DEVICE_TARGET_ABS=${AOSP_ABS}${DEVICE_TARGET_REL}
+
+VENDOR_SYMBOLS_REL=/symbols/system/vendor/lib
+VENDOR_SYMBOLS_ABS=${DEVICE_TARGET_ABS}/${DEVICE}/${VENDOR_SYMBOLS_REL}
+
+# The name of the object built by the test vendor library.
+TEST_VENDOR_LIB=test-vendor.so
+# The name of the regular vendor object to be replaced by $TEST_VENDOR_LIB.
+VENDOR_LIB=libbt-vendor.so
+# The config file specifying controller properties.
+CONTROLLER_PROPERTIES=controller_properties.json
+
+if [[ "$#" -eq 4 && $3 == "--test-channel" ]]; then
+ TEST_CHANNEL_PORT=$4
+ TEST_CHANNEL_REL=/scripts
+ TEST_CHANNEL_ABS=${TEST_VENDOR_LIB_ABS}${TEST_CHANNEL_REL}
+
+ # Start logcat in a subshell.
+ x-terminal-emulator -e "scripts/build_and_run.sh ${AOSP_ABS} ${DEVICE}"
+
+ echo "Setting up build environment."
+ cd ${AOSP_ABS}
+ source build/envsetup.sh
+
+ # Forward local port to the same port on the device.
+ echo "Forwarding port ${TEST_CHANNEL_PORT} to device."
+ adb forward tcp:${TEST_CHANNEL_PORT} tcp:${TEST_CHANNEL_PORT}
+
+ # Turn Bluetooth on. Requires user approval via a dialog on the device.
+ echo "Enabling Bluetooth. Please see dialog on device."
+ adb shell am start -a android.bluetooth.adapter.action.REQUEST_ENABLE
+
+ # Start the test channel once Bluetooth is on and logcat has started.
+ read -p "Press [ENTER] once Bluetooth is enabling AND logcat has started."
+
+ # Start the test channel.
+ python ${TEST_CHANNEL_ABS}/test_channel.py localhost ${TEST_CHANNEL_PORT}
+else
+ echo "Setting up build environment."
+ cd ${AOSP_ABS}
+ source build/envsetup.sh
+
+ echo "Navigating to test vendor library: ${TEST_VENDOR_LIB_ABS}"
+ cd ${TEST_VENDOR_LIB_ABS}
+
+ echo "Building test vendor library."
+ mm
+
+ echo "Remounting device rootfs."
+ adb shell mount -o remount,rw /
+ adb remount
+
+ # Replace the actual vendor library with the test vendor library.
+ mv ${DEVICE_TARGET_ABS}/${DEVICE}/system/lib/${TEST_VENDOR_LIB} \
+ ${VENDOR_SYMBOLS_ABS}/${VENDOR_LIB}
+
+ # Push the test vendor library to the device.
+ echo "Pushing the test vendor library to device: $DEVICE"
+ adb push ${VENDOR_SYMBOLS_ABS}/${VENDOR_LIB} /vendor/lib
+
+ echo "Pushing controller properties."
+ adb push ${TEST_VENDOR_LIB_ABS}/data/${CONTROLLER_PROPERTIES} /etc/bluetooth/
+
+ echo "Pushing libevent."
+ adb push ${DEVICE_TARGET_ABS}/${DEVICE}/system/lib/libevent.so /system/lib/
+
+ echo "Pushing libchrome."
+ adb push ${DEVICE_TARGET_ABS}/${DEVICE}/system/lib/libchrome.so /system/lib/
+
+ # Clear logcat.
+ adb logcat -c
+
+ # Run logcat with filters.
+ adb logcat bt_btif:D bt_btif_core:D bt_hci:D bt_main:D bt_vendor:D \
+ bte_logmsg:D command_packet:D dual_mode_controller:D event_packet:D \
+ hci_transport:D hci_handler:D packet:D packet_stream:D \
+ test_channel_transport:D vendor_manager:D *:S
+fi
--- /dev/null
+#
+# Copyright 2015 The Android Open Source Project
+#
+# 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.
+#
+
+"""Script for sending testing parameters and commands to a Bluetooth device.
+
+This script provides a simple shell interface for sending data at run-time to a
+Bluetooth device. It is intended to be used in tandem with the test vendor
+library project.
+
+Usage:
+ Option A: Script
+ 1. Run build_and_run.sh in scripts/ with the --test-channel flag set and the
+ port to use for the test channel.
+ Option B: Manual
+ 1. Choose a port to use for the test channel. Use 'adb forward tcp:<port>
+ tcp:<port>' to forward the port to the device.
+ 2. In a separate shell, build and push the test vendor library to the device
+ using the script mentioned in option A (i.e. without the --test-channel flag
+ set).
+ 3. Once logcat has started, turn Bluetooth on from the device.
+ 4. Run this program, in the shell from step 1, the port, also from step 1,
+ as arguments.
+"""
+
+#!/usr/bin/env python
+
+import cmd
+import random
+import socket
+import string
+import struct
+import sys
+
+DEVICE_NAME_LENGTH = 6
+DEVICE_ADDRESS_LENGTH = 6
+
+# Used to generate fake device names and addresses during discovery.
+def generate_random_name():
+ return ''.join(random.SystemRandom().choice(string.ascii_uppercase + \
+ string.digits) for _ in range(DEVICE_NAME_LENGTH))
+
+def generate_random_address():
+ return ''.join(random.SystemRandom().choice(string.digits) for _ in \
+ range(DEVICE_ADDRESS_LENGTH))
+
+class Connection(object):
+ """Simple wrapper class for a socket object.
+
+ Attributes:
+ socket: The underlying socket created for the specified address and port.
+ """
+
+ def __init__(self, port):
+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self._socket.connect(('localhost', port))
+
+ def close(self):
+ self._socket.close()
+
+ def send(self, data):
+ self._socket.sendall(data)
+
+class TestChannel(object):
+ """Checks outgoing commands and sends them once verified.
+
+ Attributes:
+ connection: The connection to the test vendor library that commands are sent
+ on.
+ """
+
+ def __init__(self, port):
+ self._connection = Connection(port)
+ self._discovered_devices = DeviceManager()
+
+ def discover_new_device(self, name=None, address=None):
+ device = Device(name, address)
+ self._discovered_devices.add_device(device)
+ return device
+
+ def close(self):
+ self._connection.close()
+
+ def send_command(self, name, args):
+ name_size = len(name)
+ args_size = len(args)
+ self.lint_command(name, args, name_size, args_size)
+ encoded_name = chr(name_size) + name
+ encoded_args = chr(args_size) + ''.join(chr(len(arg)) + arg for arg in args)
+ command = encoded_name + encoded_args
+ self._connection.send(command)
+
+ def lint_command(self, name, args, name_size, args_size):
+ assert name_size == len(name) and args_size == len(args)
+ try:
+ name.encode('utf-8')
+ for arg in args:
+ arg.encode('utf-8')
+ except UnicodeError:
+ print 'Unrecognized characters.'
+ raise
+ if name_size > 255 or args_size > 255:
+ raise ValueError # Size must be encodable in one octet.
+ for arg in args:
+ if len(arg) > 255:
+ raise ValueError # Size must be encodable in one octet.
+
+class DeviceManager(object):
+ """Maintains the active fake devices that have been "discovered".
+
+ Attributes:
+ device_list: Maps device addresses (keys) to devices (values).
+ """
+
+ def __init__(self):
+ self.device_list = {}
+
+ def add_device(self, device):
+ self.device_list[device.get_address()] = device
+
+class Device(object):
+ """A fake device to be returned in inquiry and scan results. Note that if an
+ explicit name or address is not provided, a random string of characters
+ is used.
+
+ Attributes:
+ name: The device name for use in extended results.
+ address: The BD address of the device.
+ """
+
+ def __init__(self, name=None, address=None):
+ # TODO(dennischeng): Generate device properties more robustly.
+ self._name = generate_random_name() if name is None else name
+ self._address = generate_random_address() if address is None else address
+
+ def get_name(self):
+ return self._name
+
+ def get_address(self):
+ return self._address
+
+class TestChannelShell(cmd.Cmd):
+ """Shell for sending test channel data to controller.
+
+ Manages the test channel to the controller and defines a set of commands the
+ user can send to the controller as well. These commands are processed parallel
+ to commands sent from the device stack and used to provide additional
+ debugging/testing capabilities.
+
+ Attributes:
+ test_channel: The communication channel to send data to the controller.
+ """
+
+ def __init__(self, test_channel):
+ print 'Type \'help\' for more information.'
+ cmd.Cmd.__init__(self)
+ self._test_channel = test_channel
+
+ def do_clear(self, args):
+ """
+ Arguments: None.
+ Resets the controller to its original, unmodified state.
+ """
+ self._test_channel.send_command('CLEAR', [])
+
+ def do_clear_event_delay(self, args):
+ """
+ Arguments: None.
+ Clears the response delay set by set_event_delay.
+ """
+ self._test_channel.send_command('CLEAR_EVENT_DELAY', args.split())
+
+ def do_discover(self, args):
+ """
+ Arguments: name_1 name_2 ...
+ Sends an inquiry result for named device(s). If no names are provided, a
+ random name is used instead.
+ """
+ if len(args) == 0:
+ args = generate_random_name()
+ device_list = [self._test_channel.discover_new_device(arg) for arg in \
+ args.split()]
+ device_names_and_addresses = []
+ for device in device_list:
+ device_names_and_addresses.append(device.get_name())
+ device_names_and_addresses.append(device.get_address())
+ self._test_channel.send_command('DISCOVER', device_names_and_addresses)
+
+ def do_set_event_delay(self, args):
+ """
+ Arguments: interval_in_ms
+ Sets the response delay for all event packets sent from the controller back
+ to the HCI.
+ """
+ self._test_channel.send_command('SET_EVENT_DELAY', args.split())
+
+ def do_timeout_all(self, args):
+ """
+ Arguments: None.
+ Causes all HCI commands to timeout.
+ """
+ self._test_channel.send_command('TIMEOUT_ALL', [])
+
+ def do_quit(self, args):
+ """
+ Arguments: None.
+ Exits the test channel.
+ """
+ self._test_channel.send_command('CLOSE_TEST_CHANNEL', [])
+ self._test_channel.close()
+ print 'Goodbye.'
+ return True
+
+def main(argv):
+ if len(argv) != 2:
+ print 'Usage: python test_channel.py [port]'
+ return
+ try:
+ port = int(argv[1])
+ except ValueError:
+ print 'Error parsing port.'
+ else:
+ try:
+ test_channel = TestChannel(port)
+ except socket.error, e:
+ print 'Error connecting to socket: %s' % e
+ except:
+ print 'Error creating test channel (check argument).'
+ else:
+ test_channel_shell = TestChannelShell(test_channel)
+ test_channel_shell.prompt = '$ '
+ test_channel_shell.cmdloop()
+
+if __name__ == '__main__':
+ main(sys.argv)
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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_vendor"
+
+#include "vendor_manager.h"
+
+#include "base/logging.h"
+
+extern "C" {
+#include "osi/include/log.h"
+
+#include <unistd.h>
+} // extern "C"
+
+namespace test_vendor_lib {
+
+// Initializes vendor manager for test controller. |p_cb| are the callbacks to
+// be in TestVendorOp(). |local_bdaddr| points to the address of the Bluetooth
+// device. Returns 0 on success, -1 on error.
+static int TestVendorInitialize(const bt_vendor_callbacks_t* p_cb,
+ unsigned char* /* local_bdaddr */) {
+ LOG_INFO(LOG_TAG, "Initializing test controller.");
+ CHECK(p_cb);
+
+ VendorManager::Initialize();
+ VendorManager* manager = VendorManager::Get();
+ manager->SetVendorCallbacks(*(const_cast<bt_vendor_callbacks_t*>(p_cb)));
+ return manager->Run() ? 0 : -1;
+}
+
+// Vendor specific operations. |opcode| is the opcode for Bluedroid's vendor op
+// definitions. |param| points to operation specific arguments. Return value is
+// dependent on the operation invoked, or -1 on error.
+static int TestVendorOp(bt_vendor_opcode_t opcode, void* param) {
+ LOG_INFO(LOG_TAG, "Opcode received in vendor library: %d", opcode);
+
+ VendorManager* manager = VendorManager::Get();
+ CHECK(manager);
+
+ switch (opcode) {
+ case BT_VND_OP_POWER_CTRL: {
+ LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_POWER_CTRL");
+ int* state = static_cast<int*>(param);
+ if (*state == BT_VND_PWR_OFF)
+ LOG_INFO(LOG_TAG, "Turning Bluetooth off.");
+ else if (*state == BT_VND_PWR_ON)
+ LOG_INFO(LOG_TAG, "Turning Bluetooth on.");
+ return 0;
+ }
+
+ // Give the HCI its fd to communicate with the HciTransport.
+ case BT_VND_OP_USERIAL_OPEN: {
+ LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_USERIAL_OPEN");
+ int* fd_list = static_cast<int*>(param);
+ fd_list[0] = manager->GetHciFd();
+ LOG_INFO(LOG_TAG, "Setting HCI's fd to: %d", fd_list[0]);
+ return 1;
+ }
+
+ // Close the HCI's file descriptor.
+ case BT_VND_OP_USERIAL_CLOSE:
+ LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_USERIAL_CLOSE");
+ LOG_INFO(LOG_TAG, "Closing HCI's fd (fd: %d)", manager->GetHciFd());
+ manager->CloseHciFd();
+ return 1;
+
+ case BT_VND_OP_FW_CFG:
+ LOG_INFO(LOG_TAG, "Unsupported op: BT_VND_OP_FW_CFG");
+ manager->GetVendorCallbacks().fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+ return -1;
+
+ default:
+ LOG_INFO(LOG_TAG, "Op not recognized.");
+ return -1;
+ }
+ return 0;
+}
+
+// Closes the vendor interface and cleans up the global vendor manager object.
+static void TestVendorCleanUp(void) {
+ LOG_INFO(LOG_TAG, "Cleaning up vendor library.");
+ VendorManager::CleanUp();
+}
+
+} // namespace test_vendor_lib
+
+// Entry point of DLib.
+const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
+ sizeof(bt_vendor_interface_t),
+ test_vendor_lib::TestVendorInitialize,
+ test_vendor_lib::TestVendorOp,
+ test_vendor_lib::TestVendorCleanUp
+};
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 "command_packet"
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+
+extern "C" {
+#include "hci/include/hci_hal.h"
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+} // extern "C"
+
+namespace test_vendor_lib {
+
+CommandPacket::CommandPacket() : Packet(DATA_TYPE_COMMAND) {}
+
+uint16_t CommandPacket::GetOpcode() const {
+ return 0 | (GetHeader()[0] | (GetHeader()[1] << 8));
+}
+
+uint8_t CommandPacket::GetOGF() const {
+ return HCI_OGF(GetOpcode());
+}
+
+uint16_t CommandPacket::GetOCF() const {
+ return HCI_OCF(GetOpcode());
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 "dual_mode_controller"
+
+#include "vendor_libs/test_vendor_lib/include/dual_mode_controller.h"
+
+#include "base/logging.h"
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/values.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+extern "C" {
+#include "stack/include/hcidefs.h"
+#include "osi/include/log.h"
+} // extern "C"
+
+namespace {
+
+// Included in certain events to indicate success (specific to the event
+// context).
+const uint8_t kSuccessStatus = 0;
+
+// The default number encoded in event packets to indicate to the HCI how many
+// command packets it can send to the controller.
+const uint8_t kNumHciCommandPackets = 1;
+
+// The location of the config file loaded to populate controller attributes.
+const std::string kControllerPropertiesFile =
+ "/etc/bluetooth/controller_properties.json";
+
+// Inquiry modes for specifiying inquiry result formats.
+const uint8_t kStandardInquiry = 0x00;
+const uint8_t kRssiInquiry = 0x01;
+const uint8_t kExtendedOrRssiInquiry = 0x02;
+
+// The bd address of another (fake) device.
+const std::vector<uint8_t> kOtherDeviceBdAddress = {6, 5, 4, 3, 2, 1};
+
+// Fake inquiry response for a fake device.
+const std::vector<uint8_t> kPageScanRepetitionMode = {0};
+const std::vector<uint8_t> kPageScanPeriodMode = {0};
+const std::vector<uint8_t> kPageScanMode = {0};
+const std::vector<uint8_t> kClassOfDevice = {1, 2, 3};
+const std::vector<uint8_t> kClockOffset = {1, 2};
+
+void LogCommand(const char* command) {
+ LOG_INFO(LOG_TAG, "Controller performing command: %s", command);
+}
+
+// Functions used by JSONValueConverter to read stringified JSON into Properties
+// object.
+bool ParseUint8t(const base::StringPiece& value, uint8_t* field) {
+ *field = std::stoi(value.as_string());
+ return true;
+}
+
+bool ParseUint16t(const base::StringPiece& value, uint16_t* field) {
+ *field = std::stoi(value.as_string());
+ return true;
+}
+
+bool ParseUint8tVector(const base::StringPiece& value,
+ std::vector<uint8_t>* field) {
+ for (char& c : value.as_string())
+ field->push_back(c - '0');
+ return true;
+}
+
+} // namespace
+
+namespace test_vendor_lib {
+
+void DualModeController::SendCommandComplete(
+ uint16_t command_opcode,
+ const std::vector<uint8_t>& return_parameters) const {
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteEvent(
+ kNumHciCommandPackets, command_opcode, return_parameters);
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::SendCommandCompleteSuccess(
+ uint16_t command_opcode) const {
+ SendCommandComplete(command_opcode, {kSuccessStatus});
+}
+
+void DualModeController::SendCommandStatus(uint8_t status,
+ uint16_t command_opcode) const {
+ std::unique_ptr<EventPacket> command_status =
+ EventPacket::CreateCommandStatusEvent(status, kNumHciCommandPackets,
+ command_opcode);
+ send_event_(std::move(command_status));
+}
+
+void DualModeController::SendCommandStatusSuccess(
+ uint16_t command_opcode) const {
+ SendCommandStatus(kSuccessStatus, command_opcode);
+}
+
+void DualModeController::SendInquiryResult() const {
+ std::unique_ptr<EventPacket> inquiry_result =
+ EventPacket::CreateInquiryResultEvent(
+ 1, kOtherDeviceBdAddress, kPageScanRepetitionMode,
+ kPageScanPeriodMode, kPageScanMode, kClassOfDevice, kClockOffset);
+ send_event_(std::move(inquiry_result));
+}
+
+void DualModeController::SendExtendedInquiryResult(
+ const std::string& name, const std::string& address) const {
+ std::vector<uint8_t> rssi = {0};
+ std::vector<uint8_t> extended_inquiry_data = {name.length() + 1, 0x09};
+ std::copy(name.begin(), name.end(),
+ std::back_inserter(extended_inquiry_data));
+ std::vector<uint8_t> bd_address(address.begin(), address.end());
+ // TODO(dennischeng): Use constants for parameter sizes, here and elsewhere.
+ while (extended_inquiry_data.size() < 240) {
+ extended_inquiry_data.push_back(0);
+ }
+ std::unique_ptr<EventPacket> extended_inquiry_result =
+ EventPacket::CreateExtendedInquiryResultEvent(
+ bd_address, kPageScanRepetitionMode, kPageScanPeriodMode,
+ kClassOfDevice, kClockOffset, rssi, extended_inquiry_data);
+ send_event_(std::move(extended_inquiry_result));
+}
+
+DualModeController::DualModeController()
+ : state_(kStandby),
+ test_channel_state_(kNone),
+ properties_(kControllerPropertiesFile) {
+#define SET_HANDLER(opcode, method) \
+ active_hci_commands_[opcode] = \
+ std::bind(&DualModeController::method, this, std::placeholders::_1);
+ SET_HANDLER(HCI_RESET, HciReset);
+ SET_HANDLER(HCI_READ_BUFFER_SIZE, HciReadBufferSize);
+ SET_HANDLER(HCI_HOST_BUFFER_SIZE, HciHostBufferSize);
+ SET_HANDLER(HCI_READ_LOCAL_VERSION_INFO, HciReadLocalVersionInformation);
+ SET_HANDLER(HCI_READ_BD_ADDR, HciReadBdAddr);
+ SET_HANDLER(HCI_READ_LOCAL_SUPPORTED_CMDS, HciReadLocalSupportedCommands);
+ SET_HANDLER(HCI_READ_LOCAL_EXT_FEATURES, HciReadLocalExtendedFeatures);
+ SET_HANDLER(HCI_WRITE_SIMPLE_PAIRING_MODE, HciWriteSimplePairingMode);
+ SET_HANDLER(HCI_WRITE_LE_HOST_SUPPORT, HciWriteLeHostSupport);
+ SET_HANDLER(HCI_SET_EVENT_MASK, HciSetEventMask);
+ SET_HANDLER(HCI_WRITE_INQUIRY_MODE, HciWriteInquiryMode);
+ SET_HANDLER(HCI_WRITE_PAGESCAN_TYPE, HciWritePageScanType);
+ SET_HANDLER(HCI_WRITE_INQSCAN_TYPE, HciWriteInquiryScanType);
+ SET_HANDLER(HCI_WRITE_CLASS_OF_DEVICE, HciWriteClassOfDevice);
+ SET_HANDLER(HCI_WRITE_PAGE_TOUT, HciWritePageTimeout);
+ SET_HANDLER(HCI_WRITE_DEF_POLICY_SETTINGS, HciWriteDefaultLinkPolicySettings);
+ SET_HANDLER(HCI_READ_LOCAL_NAME, HciReadLocalName);
+ SET_HANDLER(HCI_CHANGE_LOCAL_NAME, HciWriteLocalName);
+ SET_HANDLER(HCI_WRITE_EXT_INQ_RESPONSE, HciWriteExtendedInquiryResponse);
+ SET_HANDLER(HCI_WRITE_VOICE_SETTINGS, HciWriteVoiceSetting);
+ SET_HANDLER(HCI_WRITE_CURRENT_IAC_LAP, HciWriteCurrentIacLap);
+ SET_HANDLER(HCI_WRITE_INQUIRYSCAN_CFG, HciWriteInquiryScanActivity);
+ SET_HANDLER(HCI_WRITE_SCAN_ENABLE, HciWriteScanEnable);
+ SET_HANDLER(HCI_SET_EVENT_FILTER, HciSetEventFilter);
+ SET_HANDLER(HCI_INQUIRY, HciInquiry);
+ SET_HANDLER(HCI_INQUIRY_CANCEL, HciInquiryCancel);
+ SET_HANDLER(HCI_DELETE_STORED_LINK_KEY, HciDeleteStoredLinkKey);
+ SET_HANDLER(HCI_RMT_NAME_REQUEST, HciRemoteNameRequest);
+#undef SET_HANDLER
+
+#define SET_TEST_HANDLER(command_name, method) \
+ active_test_channel_commands_[command_name] = \
+ std::bind(&DualModeController::method, this, std::placeholders::_1);
+ SET_TEST_HANDLER("CLEAR", TestChannelClear);
+ SET_TEST_HANDLER("CLEAR_EVENT_DELAY", TestChannelClearEventDelay);
+ SET_TEST_HANDLER("DISCOVER", TestChannelDiscover);
+ SET_TEST_HANDLER("SET_EVENT_DELAY", TestChannelSetEventDelay);
+ SET_TEST_HANDLER("TIMEOUT_ALL", TestChannelTimeoutAll);
+#undef SET_TEST_HANDLER
+}
+
+void DualModeController::RegisterHandlersWithHciTransport(
+ HciTransport& transport) {
+ transport.RegisterCommandHandler(std::bind(&DualModeController::HandleCommand,
+ this, std::placeholders::_1));
+}
+
+void DualModeController::RegisterHandlersWithTestChannelTransport(
+ TestChannelTransport& transport) {
+ transport.RegisterCommandHandler(
+ std::bind(&DualModeController::HandleTestChannelCommand, this,
+ std::placeholders::_1, std::placeholders::_2));
+}
+
+void DualModeController::HandleTestChannelCommand(
+ const std::string& name, const std::vector<std::string>& args) {
+ if (active_test_channel_commands_.count(name) == 0)
+ return;
+ active_test_channel_commands_[name](args);
+}
+
+void DualModeController::HandleCommand(
+ std::unique_ptr<CommandPacket> command_packet) {
+ uint16_t opcode = command_packet->GetOpcode();
+ LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode,
+ command_packet->GetOGF(), command_packet->GetOCF());
+
+ // The command hasn't been registered with the handler yet. There is nothing
+ // to do.
+ if (active_hci_commands_.count(opcode) == 0)
+ return;
+ else if (test_channel_state_ == kTimeoutAll)
+ return;
+ active_hci_commands_[opcode](command_packet->GetPayload());
+}
+
+void DualModeController::RegisterEventChannel(
+ std::function<void(std::unique_ptr<EventPacket>)> callback) {
+ send_event_ = callback;
+}
+
+void DualModeController::RegisterDelayedEventChannel(
+ std::function<void(std::unique_ptr<EventPacket>, base::TimeDelta)>
+ callback) {
+ send_delayed_event_ = callback;
+ SetEventDelay(0);
+}
+
+void DualModeController::SetEventDelay(int64_t delay) {
+ if (delay < 0)
+ delay = 0;
+ send_event_ = std::bind(send_delayed_event_, std::placeholders::_1,
+ base::TimeDelta::FromMilliseconds(delay));
+}
+
+void DualModeController::TestChannelClear(
+ const std::vector<std::string>& args) {
+ LogCommand("TestChannel Clear");
+ test_channel_state_ = kNone;
+ SetEventDelay(0);
+}
+
+void DualModeController::TestChannelDiscover(
+ const std::vector<std::string>& args) {
+ LogCommand("TestChannel Discover");
+ for (size_t i = 0; i < args.size()-1; i+=2)
+ SendExtendedInquiryResult(args[i], args[i+1]);
+}
+
+void DualModeController::TestChannelTimeoutAll(
+ const std::vector<std::string>& args) {
+ LogCommand("TestChannel Timeout All");
+ test_channel_state_ = kTimeoutAll;
+}
+
+void DualModeController::TestChannelSetEventDelay(
+ const std::vector<std::string>& args) {
+ LogCommand("TestChannel Set Event Delay");
+ test_channel_state_ = kDelayedResponse;
+ SetEventDelay(std::stoi(args[0]));
+}
+
+void DualModeController::TestChannelClearEventDelay(
+ const std::vector<std::string>& args) {
+ LogCommand("TestChannel Clear Event Delay");
+ test_channel_state_ = kNone;
+ SetEventDelay(0);
+}
+
+void DualModeController::HciReset(const std::vector<uint8_t>& /* args */) {
+ LogCommand("Reset");
+ state_ = kStandby;
+ SendCommandCompleteSuccess(HCI_RESET);
+}
+
+void DualModeController::HciReadBufferSize(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Read Buffer Size");
+ SendCommandComplete(HCI_READ_BUFFER_SIZE, properties_.GetBufferSize());
+}
+
+void DualModeController::HciHostBufferSize(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Host Buffer Size");
+ SendCommandCompleteSuccess(HCI_HOST_BUFFER_SIZE);
+}
+
+void DualModeController::HciReadLocalVersionInformation(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Read Local Version Information");
+ SendCommandComplete(HCI_READ_LOCAL_VERSION_INFO,
+ properties_.GetLocalVersionInformation());
+}
+
+void DualModeController::HciReadBdAddr(const std::vector<uint8_t>& /* args */) {
+ LogCommand("Read Bd Addr");
+ std::vector<uint8_t> bd_address_with_status = properties_.GetBdAddress();
+ bd_address_with_status.insert(bd_address_with_status.begin(),
+ kSuccessStatus);
+ SendCommandComplete(HCI_READ_BD_ADDR, bd_address_with_status);
+}
+
+void DualModeController::HciReadLocalSupportedCommands(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Read Local Supported Commands");
+ SendCommandComplete(HCI_READ_LOCAL_SUPPORTED_CMDS,
+ properties_.GetLocalSupportedCommands());
+}
+
+void DualModeController::HciReadLocalExtendedFeatures(
+ const std::vector<uint8_t>& args) {
+ LogCommand("Read Local Extended Features");
+ SendCommandComplete(HCI_READ_LOCAL_EXT_FEATURES,
+ properties_.GetLocalExtendedFeatures(args[0]));
+}
+
+void DualModeController::HciWriteSimplePairingMode(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Simple Pairing Mode");
+ SendCommandCompleteSuccess(HCI_WRITE_SIMPLE_PAIRING_MODE);
+}
+
+void DualModeController::HciWriteLeHostSupport(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Le Host Support");
+ SendCommandCompleteSuccess(HCI_WRITE_LE_HOST_SUPPORT);
+}
+
+void DualModeController::HciSetEventMask(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Set Event Mask");
+ SendCommandCompleteSuccess(HCI_SET_EVENT_MASK);
+}
+
+void DualModeController::HciWriteInquiryMode(const std::vector<uint8_t>& args) {
+ LogCommand("Write Inquiry Mode");
+ CHECK(args.size() == 1);
+ inquiry_mode_ = args[0];
+ SendCommandCompleteSuccess(HCI_WRITE_INQUIRY_MODE);
+}
+
+void DualModeController::HciWritePageScanType(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Page Scan Type");
+ SendCommandCompleteSuccess(HCI_WRITE_PAGESCAN_TYPE);
+}
+
+void DualModeController::HciWriteInquiryScanType(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Inquiry Scan Type");
+ SendCommandCompleteSuccess(HCI_WRITE_INQSCAN_TYPE);
+}
+
+void DualModeController::HciWriteClassOfDevice(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Class Of Device");
+ SendCommandCompleteSuccess(HCI_WRITE_CLASS_OF_DEVICE);
+}
+
+void DualModeController::HciWritePageTimeout(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Page Timeout");
+ SendCommandCompleteSuccess(HCI_WRITE_PAGE_TOUT);
+}
+
+void DualModeController::HciWriteDefaultLinkPolicySettings(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Default Link Policy Settings");
+ SendCommandCompleteSuccess(HCI_WRITE_DEF_POLICY_SETTINGS);
+}
+
+void DualModeController::HciReadLocalName(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Get Local Name");
+ SendCommandComplete(HCI_READ_LOCAL_NAME, properties_.GetLocalName());
+}
+
+void DualModeController::HciWriteLocalName(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Local Name");
+ SendCommandCompleteSuccess(HCI_CHANGE_LOCAL_NAME);
+}
+
+void DualModeController::HciWriteExtendedInquiryResponse(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Extended Inquiry Response");
+ SendCommandCompleteSuccess(HCI_WRITE_EXT_INQ_RESPONSE);
+}
+
+void DualModeController::HciWriteVoiceSetting(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Voice Setting");
+ SendCommandCompleteSuccess(HCI_WRITE_VOICE_SETTINGS);
+}
+
+void DualModeController::HciWriteCurrentIacLap(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Current IAC LAP");
+ SendCommandCompleteSuccess(HCI_WRITE_CURRENT_IAC_LAP);
+}
+
+void DualModeController::HciWriteInquiryScanActivity(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Inquiry Scan Activity");
+ SendCommandCompleteSuccess(HCI_WRITE_INQUIRYSCAN_CFG);
+}
+
+void DualModeController::HciWriteScanEnable(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Write Scan Enable");
+ SendCommandCompleteSuccess(HCI_WRITE_SCAN_ENABLE);
+}
+
+void DualModeController::HciSetEventFilter(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Set Event Filter");
+ SendCommandCompleteSuccess(HCI_SET_EVENT_FILTER);
+}
+
+void DualModeController::HciInquiry(const std::vector<uint8_t>& /* args */) {
+ LogCommand("Inquiry");
+ state_ = kInquiry;
+ SendCommandStatusSuccess(HCI_INQUIRY);
+ switch (inquiry_mode_) {
+ case (kStandardInquiry):
+ SendInquiryResult();
+ break;
+
+ case (kRssiInquiry):
+ LOG_INFO(LOG_TAG, "RSSI Inquiry Mode currently not supported.");
+ break;
+
+ case (kExtendedOrRssiInquiry):
+ SendExtendedInquiryResult("FooBar", "123456");
+ break;
+ }
+}
+
+void DualModeController::HciInquiryCancel(
+ const std::vector<uint8_t>& /* args */) {
+ LogCommand("Inquiry Cancel");
+ CHECK(state_ == kInquiry);
+ state_ = kStandby;
+ SendCommandCompleteSuccess(HCI_INQUIRY_CANCEL);
+}
+
+void DualModeController::HciDeleteStoredLinkKey(
+ const std::vector<uint8_t>& args) {
+ LogCommand("Delete Stored Link Key");
+ /* Check the last octect in |args|. If it is 0, delete only the link key for
+ * the given BD_ADDR. If is is 1, delete all stored link keys. */
+ SendCommandComplete(HCI_DELETE_STORED_LINK_KEY, {1});
+}
+
+void DualModeController::HciRemoteNameRequest(
+ const std::vector<uint8_t>& args) {
+ LogCommand("Remote Name Request");
+ SendCommandStatusSuccess(HCI_RMT_NAME_REQUEST);
+}
+
+DualModeController::Properties::Properties(const std::string& file_name)
+ : local_supported_commands_size_(64), local_name_size_(248) {
+ std::string properties_raw;
+ if (!base::ReadFileToString(base::FilePath(file_name), &properties_raw))
+ LOG_INFO(LOG_TAG, "Error reading controller properties from file.");
+
+ scoped_ptr<base::Value> properties_value_ptr =
+ base::JSONReader::Read(properties_raw);
+ if (properties_value_ptr.get() == nullptr)
+ LOG_INFO(LOG_TAG,
+ "Error controller properties may consist of ill-formed JSON.");
+
+ // Get the underlying base::Value object, which is of type
+ // base::Value::TYPE_DICTIONARY, and read it into member variables.
+ base::Value& properties_dictionary = *(properties_value_ptr.get());
+ base::JSONValueConverter<DualModeController::Properties> converter;
+
+ if (!converter.Convert(properties_dictionary, this))
+ LOG_INFO(LOG_TAG,
+ "Error converting JSON properties into Properties object.");
+}
+
+const std::vector<uint8_t> DualModeController::Properties::GetBufferSize() {
+ return std::vector<uint8_t>(
+ {kSuccessStatus, acl_data_packet_size_, acl_data_packet_size_ >> 8,
+ sco_data_packet_size_, num_acl_data_packets_, num_acl_data_packets_ >> 8,
+ num_sco_data_packets_, num_sco_data_packets_ >> 8});
+}
+
+const std::vector<uint8_t>
+DualModeController::Properties::GetLocalVersionInformation() {
+ return std::vector<uint8_t>({kSuccessStatus, version_, revision_,
+ revision_ >> 8, lmp_pal_version_,
+ manufacturer_name_, manufacturer_name_ >> 8,
+ lmp_pal_subversion_, lmp_pal_subversion_ >> 8});
+}
+
+const std::vector<uint8_t> DualModeController::Properties::GetBdAddress() {
+ return bd_address_;
+}
+
+const std::vector<uint8_t>
+DualModeController::Properties::GetLocalExtendedFeatures(uint8_t page_number) {
+ return std::vector<uint8_t>({kSuccessStatus, page_number,
+ maximum_page_number_, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF});
+}
+
+const std::vector<uint8_t>
+DualModeController::Properties::GetLocalSupportedCommands() {
+ std::vector<uint8_t> local_supported_commands;
+ local_supported_commands.push_back(kSuccessStatus);
+ for (uint8_t i = 0; i < local_supported_commands_size_; ++i)
+ local_supported_commands.push_back(0xFF);
+ return local_supported_commands;
+}
+
+const std::vector<uint8_t> DualModeController::Properties::GetLocalName() {
+ std::vector<uint8_t> local_name;
+ local_name.push_back(kSuccessStatus);
+ for (uint8_t i = 0; i < local_name_size_; ++i)
+ local_name.push_back(0xFF);
+ return local_name;
+}
+
+// static
+void DualModeController::Properties::RegisterJSONConverter(
+ base::JSONValueConverter<DualModeController::Properties>* converter) {
+ // TODO(dennischeng): Use RegisterIntField() here?
+#define REGISTER_UINT8_T(field_name, field) \
+ converter->RegisterCustomField<uint8_t>( \
+ field_name, &DualModeController::Properties::field, &ParseUint8t);
+#define REGISTER_UINT16_T(field_name, field) \
+ converter->RegisterCustomField<uint16_t>( \
+ field_name, &DualModeController::Properties::field, &ParseUint16t);
+ REGISTER_UINT16_T("AclDataPacketSize", acl_data_packet_size_);
+ REGISTER_UINT8_T("ScoDataPacketSize", sco_data_packet_size_);
+ REGISTER_UINT16_T("NumAclDataPackets", num_acl_data_packets_);
+ REGISTER_UINT16_T("NumScoDataPackets", num_sco_data_packets_);
+ REGISTER_UINT8_T("Version", version_);
+ REGISTER_UINT16_T("Revision", revision_);
+ REGISTER_UINT8_T("LmpPalVersion", lmp_pal_version_);
+ REGISTER_UINT16_T("ManufacturerName", manufacturer_name_);
+ REGISTER_UINT16_T("LmpPalSubversion", lmp_pal_subversion_);
+ REGISTER_UINT8_T("MaximumPageNumber", maximum_page_number_);
+ converter->RegisterCustomField<std::vector<uint8_t>>(
+ "BdAddress", &DualModeController::Properties::bd_address_,
+ &ParseUint8tVector);
+#undef REGISTER_UINT8_T
+#undef REGISTER_UINT16_T
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 "event_packet"
+
+#define VECTOR_COPY_TO_END(source, destination) \
+ std::copy(source.begin(), source.end(), std::back_inserter(destination));
+
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+
+extern "C" {
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+} // extern "C"
+
+namespace test_vendor_lib {
+
+EventPacket::EventPacket(uint8_t event_code,
+ const std::vector<uint8_t>& payload)
+ : Packet(DATA_TYPE_EVENT) {
+ Encode({event_code, static_cast<uint8_t>(payload.size())}, payload);
+}
+
+uint8_t EventPacket::GetEventCode() const {
+ return GetHeader()[0];
+}
+
+// static
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteEvent(
+ uint8_t num_hci_command_packets, uint16_t command_opcode,
+ const std::vector<uint8_t>& event_return_parameters) {
+ size_t payload_size = sizeof(num_hci_command_packets) +
+ sizeof(command_opcode) + event_return_parameters.size();
+
+ std::vector<uint8_t> payload;
+ payload.reserve(payload_size);
+ payload.push_back(num_hci_command_packets);
+ payload.push_back(command_opcode);
+ payload.push_back(command_opcode >> 8);
+ VECTOR_COPY_TO_END(event_return_parameters, payload);
+
+ return std::unique_ptr<EventPacket>(
+ new EventPacket(HCI_COMMAND_COMPLETE_EVT, payload));
+}
+
+// static
+std::unique_ptr<EventPacket> EventPacket::CreateCommandStatusEvent(
+ uint8_t status, uint8_t num_hci_command_packets, uint16_t command_opcode) {
+ size_t payload_size =
+ sizeof(status) + sizeof(num_hci_command_packets) + sizeof(command_opcode);
+
+ std::vector<uint8_t> payload;
+ payload.reserve(payload_size);
+ payload.push_back(status);
+ payload.push_back(num_hci_command_packets);
+ payload.push_back(command_opcode);
+ payload.push_back(command_opcode >> 8);
+
+ return std::unique_ptr<EventPacket>(
+ new EventPacket(HCI_COMMAND_STATUS_EVT, payload));
+}
+
+//static
+std::unique_ptr<EventPacket> EventPacket::CreateInquiryResultEvent(
+ uint8_t num_responses, const std::vector<uint8_t>& bd_addresses,
+ const std::vector<uint8_t>& page_scan_repetition_mode,
+ const std::vector<uint8_t>& page_scan_period_mode,
+ const std::vector<uint8_t>& page_scan_mode,
+ const std::vector<uint8_t>& class_of_device,
+ const std::vector<uint8_t>& clock_offset) {
+ size_t payload_size = sizeof(num_responses) + bd_addresses.size() +
+ page_scan_repetition_mode.size() +
+ page_scan_period_mode.size() + page_scan_mode.size() +
+ class_of_device.size() + clock_offset.size();
+
+ std::vector<uint8_t> payload;
+ payload.reserve(payload_size);
+ payload.push_back(num_responses);
+ VECTOR_COPY_TO_END(bd_addresses, payload);
+ VECTOR_COPY_TO_END(page_scan_repetition_mode, payload);
+ VECTOR_COPY_TO_END(page_scan_mode, payload);
+ VECTOR_COPY_TO_END(class_of_device, payload);
+ VECTOR_COPY_TO_END(clock_offset, payload);
+
+ return std::unique_ptr<EventPacket>(
+ new EventPacket(HCI_INQUIRY_RESULT_EVT, payload));
+}
+
+//static
+std::unique_ptr<EventPacket> EventPacket::CreateExtendedInquiryResultEvent(
+ const std::vector<uint8_t>& bd_address,
+ const std::vector<uint8_t>& page_scan_repetition_mode,
+ const std::vector<uint8_t>& page_scan_period_mode,
+ const std::vector<uint8_t>& class_of_device,
+ const std::vector<uint8_t>& clock_offset,
+ const std::vector<uint8_t>& rssi,
+ const std::vector<uint8_t>& extended_inquiry_response) {
+ size_t payload_size =
+ 1 + bd_address.size() + page_scan_repetition_mode.size() +
+ page_scan_period_mode.size() + class_of_device.size() +
+ clock_offset.size() + rssi.size() + extended_inquiry_response.size();
+
+ std::vector<uint8_t> payload;
+ payload.reserve(payload_size);
+ payload.push_back(1); // Each extended inquiry result contains one device.
+ VECTOR_COPY_TO_END(bd_address, payload);
+ VECTOR_COPY_TO_END(page_scan_repetition_mode, payload);
+ VECTOR_COPY_TO_END(page_scan_period_mode, payload);
+ VECTOR_COPY_TO_END(class_of_device, payload);
+ VECTOR_COPY_TO_END(clock_offset, payload);
+ VECTOR_COPY_TO_END(rssi, payload);
+ VECTOR_COPY_TO_END(extended_inquiry_response, payload);
+
+ return std::unique_ptr<EventPacket>(
+ new EventPacket(HCI_EXTENDED_INQUIRY_RESULT_EVT, payload));
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 "hci_transport"
+
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+#include "base/logging.h"
+#include "base/bind.h"
+#include "base/thread_task_runner_handle.h"
+
+extern "C" {
+#include <sys/socket.h>
+
+#include "stack/include/hcidefs.h"
+#include "osi/include/log.h"
+} // extern "C"
+
+namespace test_vendor_lib {
+
+HciTransport::HciTransport() : weak_ptr_factory_(this) {}
+
+void HciTransport::CloseHciFd() {
+ hci_fd_.reset(nullptr);
+}
+
+void HciTransport::CloseVendorFd() {
+ vendor_fd_.reset(nullptr);
+}
+
+int HciTransport::GetHciFd() const {
+ return hci_fd_->get();
+}
+
+int HciTransport::GetVendorFd() const {
+ return vendor_fd_->get();
+}
+
+bool HciTransport::SetUp() {
+ int socketpair_fds[2];
+ // TODO(dennischeng): Use SOCK_SEQPACKET here.
+ const int success = socketpair(AF_LOCAL, SOCK_STREAM, 0, socketpair_fds);
+ if (success < 0)
+ return false;
+ hci_fd_.reset(new base::ScopedFD(socketpair_fds[0]));
+ vendor_fd_.reset(new base::ScopedFD(socketpair_fds[1]));
+ return true;
+}
+
+void HciTransport::OnFileCanReadWithoutBlocking(int fd) {
+ CHECK(fd == GetVendorFd());
+ LOG_INFO(LOG_TAG, "Event ready in HciTransport on fd: %d.", fd);
+
+ const serial_data_type_t packet_type = packet_stream_.ReceivePacketType(fd);
+ switch (packet_type) {
+ case (DATA_TYPE_COMMAND): {
+ ReceiveReadyCommand();
+ break;
+ }
+
+ case (DATA_TYPE_ACL): {
+ LOG_INFO(LOG_TAG, "ACL data packets not currently supported.");
+ break;
+ }
+
+ case (DATA_TYPE_SCO): {
+ LOG_INFO(LOG_TAG, "SCO data packets not currently supported.");
+ break;
+ }
+
+ // TODO(dennischeng): Add debug level assert here.
+ default: {
+ LOG_INFO(LOG_TAG, "Error received an invalid packet type from the HCI.");
+ break;
+ }
+ }
+}
+
+void HciTransport::ReceiveReadyCommand() const {
+ std::unique_ptr<CommandPacket> command =
+ packet_stream_.ReceiveCommand(GetVendorFd());
+ LOG_INFO(LOG_TAG, "Received command packet.");
+ command_handler_(std::move(command));
+}
+
+void HciTransport::RegisterCommandHandler(
+ std::function<void(std::unique_ptr<CommandPacket>)> callback) {
+ command_handler_ = callback;
+}
+
+void HciTransport::OnFileCanWriteWithoutBlocking(int fd) {
+ CHECK(fd == GetVendorFd());
+ if (!outbound_events_.empty()) {
+ base::TimeTicks current_time = base::TimeTicks::Now();
+ auto it = outbound_events_.begin();
+ // Check outbound events for events that can be sent, i.e. events with a
+ // timestamp before the current time. Stop sending events when
+ // |packet_stream_| fails writing.
+ for (auto it = outbound_events_.begin(); it != outbound_events_.end();) {
+ if ((*it)->GetTimeStamp() > current_time) {
+ ++it;
+ continue;
+ }
+ if (!packet_stream_.SendEvent((*it)->GetEvent(), fd))
+ return;
+ it = outbound_events_.erase(it);
+ }
+ }
+}
+
+void HciTransport::AddEventToOutboundEvents(
+ std::unique_ptr<TimeStampedEvent> event) {
+ outbound_events_.push_back(std::move(event));
+}
+
+void HciTransport::PostEventResponse(std::unique_ptr<EventPacket> event) {
+ AddEventToOutboundEvents(
+ std::make_unique<TimeStampedEvent>(std::move(event)));
+}
+
+void HciTransport::PostDelayedEventResponse(std::unique_ptr<EventPacket> event,
+ base::TimeDelta delay) {
+ // TODO(dennischeng): When it becomes available for MessageLoopForIO, use the
+ // thread's task runner to post |PostEventResponse| as a delayed task, being
+ // sure to CHECK the appropriate task runner attributes using
+ // base::ThreadTaskRunnerHandle.
+
+ // The system does not support high resolution timing and the clock could be
+ // as coarse as ~15.6 ms so the event is sent without a delay to avoid
+ // inconsistent event responses.
+ if (!base::TimeTicks::IsHighResolution()) {
+ LOG_INFO(LOG_TAG,
+ "System does not support high resolution timing. Sending event "
+ "without delay.");
+ PostEventResponse(std::move(event));
+ }
+
+ LOG_INFO(LOG_TAG, "Posting event response with delay of %lld ms.",
+ delay.InMilliseconds());
+
+ AddEventToOutboundEvents(
+ std::make_unique<TimeStampedEvent>(std::move(event), delay));
+}
+
+HciTransport::TimeStampedEvent::TimeStampedEvent(
+ std::unique_ptr<EventPacket> event, base::TimeDelta delay)
+ : event_(std::move(event)), time_stamp_(base::TimeTicks::Now() + delay) {}
+
+HciTransport::TimeStampedEvent::TimeStampedEvent(
+ std::unique_ptr<EventPacket> event)
+ : event_(std::move(event)), time_stamp_(base::TimeTicks::UnixEpoch()) {}
+
+const base::TimeTicks& HciTransport::TimeStampedEvent::GetTimeStamp() const {
+ return time_stamp_;
+}
+
+const EventPacket& HciTransport::TimeStampedEvent::GetEvent() {
+ return *(event_.get());
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 "packet"
+
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include "base/logging.h"
+
+#include <algorithm>
+
+extern "C" {
+#include "osi/include/log.h"
+} // extern "C"
+
+namespace test_vendor_lib {
+
+Packet::Packet(serial_data_type_t type) : type_(type) {}
+
+bool Packet::Encode(const std::vector<uint8_t>& header,
+ const std::vector<uint8_t>& payload) {
+ if (header.back() != payload.size())
+ return false;
+ header_ = header;
+ payload_ = payload;
+ return true;
+}
+
+const std::vector<uint8_t>& Packet::GetHeader() const {
+ // Every packet must have a header.
+ CHECK(GetHeaderSize() > 0);
+ return header_;
+}
+
+uint8_t Packet::GetHeaderSize() const {
+ return header_.size();
+}
+
+size_t Packet::GetPacketSize() const {
+ // Add one for the type octet.
+ return 1 + header_.size() + payload_.size();
+}
+
+const std::vector<uint8_t>& Packet::GetPayload() const {
+ return payload_;
+}
+
+uint8_t Packet::GetPayloadSize() const {
+ return payload_.size();
+}
+
+serial_data_type_t Packet::GetType() const {
+ return type_;
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 "packet_stream"
+
+#include "vendor_libs/test_vendor_lib/include/packet_stream.h"
+
+#include "base/logging.h"
+
+extern "C" {
+#include <errno.h>
+#include <unistd.h>
+
+#include "osi/include/log.h"
+} // extern "C"
+
+namespace test_vendor_lib {
+
+std::unique_ptr<CommandPacket> PacketStream::ReceiveCommand(int fd) const {
+ std::vector<uint8_t> header;
+ std::vector<uint8_t> payload;
+
+ if (!ReceiveAll(header, CommandPacket::kCommandHeaderSize, fd)) {
+ LOG_ERROR(LOG_TAG, "Error: receiving command header.");
+ return std::unique_ptr<CommandPacket>(nullptr);
+ }
+
+ if (!ReceiveAll(payload, header.back(), fd)) {
+ LOG_ERROR(LOG_TAG, "Error: receiving command payload.");
+ return std::unique_ptr<CommandPacket>(nullptr);
+ }
+
+ std::unique_ptr<CommandPacket> command(new CommandPacket());
+ if (!command->Encode(header, payload)) {
+ LOG_ERROR(LOG_TAG, "Error: encoding command packet.");
+ command.reset(nullptr);
+ }
+ return command;
+}
+
+serial_data_type_t PacketStream::ReceivePacketType(int fd) const {
+ LOG_INFO(LOG_TAG, "Receiving packet type.");
+
+ std::vector<uint8_t> raw_type_octet;
+
+ if (!ReceiveAll(raw_type_octet, 1, fd)) {
+ // TODO(dennischeng): Proper error handling.
+ LOG_ERROR(LOG_TAG, "Error: Could not receive packet type.");
+ }
+
+ // Check that the type octet received is in the valid range, i.e. the packet
+ // must be a command or data packet.
+ const serial_data_type_t type =
+ static_cast<serial_data_type_t>(raw_type_octet[0]);
+ if (!ValidateTypeOctet(type)) {
+ // TODO(dennischeng): Proper error handling.
+ LOG_ERROR(LOG_TAG, "Error: Received invalid packet type.");
+ }
+ return type;
+}
+
+bool PacketStream::SendEvent(const EventPacket& event, int fd) const {
+ LOG_INFO(LOG_TAG, "Sending event with event code: 0x%04X",
+ event.GetEventCode());
+ LOG_INFO(LOG_TAG, "Sending event with size: %zu octets",
+ event.GetPacketSize());
+
+ if (!SendAll({static_cast<uint8_t>(event.GetType())}, 1, fd)) {
+ LOG_ERROR(LOG_TAG, "Error: Could not send event type.");
+ return false;
+ }
+
+ if (!SendAll(event.GetHeader(), event.GetHeaderSize(), fd)) {
+ LOG_ERROR(LOG_TAG, "Error: Could not send event header.");
+ return false;
+ }
+
+ if (!SendAll(event.GetPayload(), event.GetPayloadSize(), fd)) {
+ LOG_ERROR(LOG_TAG, "Error: Could not send event payload.");
+ return false;
+ }
+ return true;
+}
+
+bool PacketStream::ValidateTypeOctet(serial_data_type_t type) const {
+ LOG_INFO(LOG_TAG, "Signal octet is 0x%02X.", type);
+ // The only types of packets that should be received from the HCI are command
+ // packets and data packets.
+ return (type >= DATA_TYPE_COMMAND) && (type <= DATA_TYPE_SCO);
+}
+
+bool PacketStream::ReceiveAll(std::vector<uint8_t>& destination,
+ size_t num_octets_to_receive, int fd) const {
+ destination.resize(num_octets_to_receive);
+ size_t octets_remaining = num_octets_to_receive;
+ while (octets_remaining > 0) {
+ const int num_octets_received =
+ read(fd, &destination[num_octets_to_receive - octets_remaining],
+ octets_remaining);
+ if (num_octets_received < 0)
+ return false;
+ octets_remaining -= num_octets_received;
+ }
+ return true;
+}
+
+bool PacketStream::SendAll(const std::vector<uint8_t>& source,
+ size_t num_octets_to_send, int fd) const {
+ CHECK(source.size() >= num_octets_to_send);
+ size_t octets_remaining = num_octets_to_send;
+ while (octets_remaining > 0) {
+ const int num_octets_sent = write(
+ fd, &source[num_octets_to_send - octets_remaining], octets_remaining);
+ if (num_octets_sent < 0)
+ return false;
+ octets_remaining -= num_octets_sent;
+ }
+ return true;
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 "test_channel_transport"
+
+#include "vendor_libs/test_vendor_lib/include/test_channel_transport.h"
+
+#include "base/logging.h"
+
+extern "C" {
+#include "osi/include/log.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+} // extern "C"
+
+namespace test_vendor_lib {
+
+TestChannelTransport::TestChannelTransport(bool enabled, int port)
+ : enabled_(enabled), port_(port) {}
+
+bool TestChannelTransport::SetUp() {
+ CHECK(enabled_);
+
+ struct sockaddr_in listen_address, test_channel_address;
+ int sockaddr_in_size = sizeof(struct sockaddr_in);
+ int listen_fd = -1;
+ int accept_fd = -1;
+ memset(&listen_address, 0, sockaddr_in_size);
+ memset(&test_channel_address, 0, sockaddr_in_size);
+
+ if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ LOG_INFO(LOG_TAG, "Error creating socket for test channel.");
+ return false;
+ }
+
+ LOG_INFO(LOG_TAG, "port: %d", port_);
+ listen_address.sin_family = AF_INET;
+ listen_address.sin_port = htons(port_);
+ listen_address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(listen_fd, reinterpret_cast<sockaddr*>(&listen_address),
+ sockaddr_in_size) < 0) {
+ LOG_INFO(LOG_TAG, "Error binding test channel listener socket to address.");
+ close(listen_fd);
+ return false;
+ }
+
+ if (listen(listen_fd, 1) < 0) {
+ LOG_INFO(LOG_TAG, "Error listening for test channel.");
+ close(listen_fd);
+ return false;
+ }
+
+ if ((accept_fd =
+ accept(listen_fd, reinterpret_cast<sockaddr*>(&test_channel_address),
+ &sockaddr_in_size)) < 0) {
+ LOG_INFO(LOG_TAG, "Error accepting test channel connection.");
+ close(listen_fd);
+ return false;
+ }
+
+ fd_.reset(new base::ScopedFD(accept_fd));
+ return GetFd() >= 0;
+}
+
+int TestChannelTransport::GetFd() {
+ return fd_->get();
+}
+
+bool TestChannelTransport::IsEnabled() {
+ return enabled_;
+}
+
+// base::MessageLoopForIO::Watcher overrides:
+void TestChannelTransport::OnFileCanReadWithoutBlocking(int fd) {
+ CHECK(fd == GetFd());
+
+ LOG_INFO(LOG_TAG, "Event ready in TestChannelTransport on fd: %d", fd);
+ uint8_t command_name_size = 0;
+ read(fd, &command_name_size, 1);
+ std::vector<uint8_t> command_name_raw;
+ command_name_raw.resize(command_name_size);
+ read(fd, &command_name_raw[0], command_name_size);
+ std::string command_name(command_name_raw.begin(), command_name_raw.end());
+ LOG_INFO(LOG_TAG, "Received command from test channel: %s",
+ command_name.data());
+
+ if (command_name == "CLOSE_TEST_CHANNEL") {
+ fd_.reset(nullptr);
+ return;
+ }
+
+ uint8_t num_args = 0;
+ read(fd, &num_args, 1);
+ LOG_INFO(LOG_TAG, "num_args: %d", num_args);
+ std::vector<std::string> args;
+ for (uint8_t i = 0; i < num_args; ++i) {
+ uint8_t arg_size = 0;
+ read(fd, &arg_size, 1);
+ std::vector<uint8_t> arg;
+ arg.resize(arg_size);
+ read(fd, &arg[0], arg_size);
+ args.push_back(std::string(arg.begin(), arg.end()));
+ }
+
+ for (size_t i = 0; i < args.size(); ++i)
+ LOG_INFO(LOG_TAG, "Command argument %d: %s", i, args[i].data());
+
+ command_handler_(command_name, args);
+}
+
+void TestChannelTransport::OnFileCanWriteWithoutBlocking(int fd) {}
+
+void TestChannelTransport::RegisterCommandHandler(
+ std::function<void(const std::string&, const std::vector<std::string>&)>
+ callback) {
+ command_handler_ = callback;
+}
+
+void TestChannelTransport::Disable() {
+ enabled_ = false;
+}
+
+} // namespace test_vendor_lib {
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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 "vendor_manager"
+
+#include "vendor_manager.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+
+extern "C" {
+#include "osi/include/log.h"
+} // extern "C"
+
+namespace test_vendor_lib {
+
+VendorManager* g_manager = nullptr;
+
+// static
+void VendorManager::CleanUp() {
+ delete g_manager;
+ g_manager = nullptr;
+}
+
+// static
+VendorManager* VendorManager::Get() {
+ // Initialize should have been called already.
+ CHECK(g_manager);
+ return g_manager;
+}
+
+// static
+void VendorManager::Initialize() {
+ CHECK(!g_manager);
+ g_manager = new VendorManager();
+}
+
+VendorManager::VendorManager()
+ : running_(false),
+ test_channel_transport_(true, 6111),
+ thread_("TestVendorLibrary"),
+ weak_ptr_factory_(this) {}
+
+bool VendorManager::Run() {
+ CHECK(!running_);
+
+ if (!transport_.SetUp()) {
+ LOG_ERROR(LOG_TAG, "Error setting up transport object.");
+ return false;
+ }
+
+ if (test_channel_transport_.IsEnabled()) {
+ LOG_INFO(LOG_TAG, "Test channel is enabled.");
+
+ if (test_channel_transport_.SetUp()) {
+ controller_.RegisterHandlersWithTestChannelTransport(
+ test_channel_transport_);
+ } else {
+ LOG_ERROR(LOG_TAG,
+ "Error setting up test channel object, continuing without it.");
+ test_channel_transport_.Disable();
+ }
+ } else {
+ LOG_INFO(LOG_TAG, "Test channel is disabled.");
+ }
+
+ controller_.RegisterHandlersWithHciTransport(transport_);
+ // TODO(dennischeng): Register PostDelayedEventResponse instead.
+ controller_.RegisterDelayedEventChannel(
+ std::bind(&HciTransport::PostDelayedEventResponse, &transport_,
+ std::placeholders::_1, std::placeholders::_2));
+
+ running_ = true;
+ if (!thread_.StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) {
+ LOG_ERROR(LOG_TAG, "Error starting TestVendorLibrary thread.");
+ running_ = false;
+ return false;
+ }
+
+ if (!PostTask(base::Bind(&VendorManager::StartWatchingOnThread,
+ weak_ptr_factory_.GetWeakPtr()))) {
+ LOG_ERROR(LOG_TAG, "Error posting StartWatchingOnThread to task runner.");
+ running_ = false;
+ return false;
+ }
+
+ return true;
+}
+
+void VendorManager::StartWatchingOnThread() {
+ CHECK(running_);
+ CHECK(base::MessageLoopForIO::IsCurrent());
+
+ if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
+ transport_.GetVendorFd(), true,
+ base::MessageLoopForIO::WATCH_READ_WRITE, &hci_watcher_,
+ &transport_)) {
+ LOG_ERROR(LOG_TAG, "Error watching vendor fd.");
+ return;
+ }
+
+ if (test_channel_transport_.IsEnabled())
+ if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
+ test_channel_transport_.GetFd(), true,
+ base::MessageLoopForIO::WATCH_READ, &test_channel_watcher_,
+ &test_channel_transport_))
+ LOG_ERROR(LOG_TAG, "Error watching test channel fd.");
+}
+
+bool VendorManager::PostTask(const base::Closure& task) {
+ return PostDelayedTask(task, base::TimeDelta::FromMilliseconds(0));
+}
+
+bool VendorManager::PostDelayedTask(const base::Closure& task,
+ base::TimeDelta delay) {
+ return thread_.task_runner()->PostDelayedTask(FROM_HERE, task, delay);
+}
+
+void VendorManager::SetVendorCallbacks(const bt_vendor_callbacks_t& callbacks) {
+ vendor_callbacks_ = callbacks;
+}
+
+const bt_vendor_callbacks_t& VendorManager::GetVendorCallbacks() const {
+ return vendor_callbacks_;
+}
+
+void VendorManager::CloseHciFd() {
+ transport_.CloseHciFd();
+}
+
+int VendorManager::GetHciFd() const {
+ return transport_.GetHciFd();
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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.
+//
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/threading/thread.h"
+
+#include <gtest/gtest.h>
+#include <functional>
+#include <mutex>
+
+extern "C" {
+#include "stack/include/hcidefs.h"
+} // extern "C"
+
+namespace {
+const std::vector<uint8_t> stub_command({DATA_TYPE_COMMAND,
+ static_cast<uint8_t>(HCI_RESET),
+ static_cast<uint8_t>(HCI_RESET >> 8),
+ 0});
+
+const int kMultiIterations = 10000;
+
+void WriteStubCommand(int fd) {
+ write(fd, &stub_command[0], stub_command.size());
+}
+
+} // namespace
+
+namespace test_vendor_lib {
+
+class HciTransportTest : public ::testing::Test {
+ public:
+ HciTransportTest()
+ : command_callback_count_(0),
+ thread_("HciTransportTest"),
+ weak_ptr_factory_(this) {
+ SetUpTransport();
+ StartThread();
+ PostStartWatchingOnThread();
+ }
+
+ ~HciTransportTest() {
+ transport_.CloseHciFd();
+ }
+
+ void CommandCallback(std::unique_ptr<CommandPacket> command) {
+ ++command_callback_count_;
+ // Ensure that the received packet matches the stub command.
+ EXPECT_EQ(DATA_TYPE_COMMAND, command->GetType());
+ EXPECT_EQ(HCI_RESET, command->GetOpcode());
+ EXPECT_EQ(0, command->GetPayloadSize());
+ transport_.CloseVendorFd();
+ }
+
+ void MultiCommandCallback(std::unique_ptr<CommandPacket> command) {
+ ++command_callback_count_;
+ // Ensure that the received packet matches the stub command.
+ EXPECT_EQ(DATA_TYPE_COMMAND, command->GetType());
+ EXPECT_EQ(HCI_RESET, command->GetOpcode());
+ EXPECT_EQ(0, command->GetPayloadSize());
+ if (command_callback_count_ == kMultiIterations)
+ transport_.CloseVendorFd();
+ }
+
+ protected:
+ // Tracks the number of commands received.
+ int command_callback_count_;
+ base::Thread thread_;
+ HciTransport transport_;
+ base::MessageLoopForIO::FileDescriptorWatcher watcher_;
+ base::WeakPtrFactory<HciTransportTest> weak_ptr_factory_;
+
+ private:
+ // Workaround because ASSERT cannot be used directly in a constructor
+ void SetUpTransport() {
+ ASSERT_TRUE(transport_.SetUp());
+ }
+
+ void StartThread() {
+ ASSERT_TRUE(thread_.StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
+ }
+
+ void PostStartWatchingOnThread() {
+ thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&HciTransportTest::StartWatchingOnThread,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ void StartWatchingOnThread() {
+ base::MessageLoopForIO* loop =
+ static_cast<base::MessageLoopForIO*>(thread_.message_loop());
+ ASSERT_TRUE(loop);
+ ASSERT_TRUE(loop->WatchFileDescriptor(
+ transport_.GetVendorFd(), true,
+ base::MessageLoopForIO::WATCH_READ_WRITE, &watcher_, &transport_));
+ }
+};
+
+TEST_F(HciTransportTest, SingleCommandCallback) {
+ transport_.RegisterCommandHandler(std::bind(
+ &HciTransportTest::CommandCallback, this, std::placeholders::_1));
+ EXPECT_EQ(0, command_callback_count_);
+ WriteStubCommand(transport_.GetHciFd());
+ thread_.Stop(); // Wait for the command handler to finish.
+ EXPECT_EQ(1, command_callback_count_);
+}
+
+TEST_F(HciTransportTest, MultiCommandCallback) {
+ transport_.RegisterCommandHandler(std::bind(
+ &HciTransportTest::MultiCommandCallback, this, std::placeholders::_1));
+ EXPECT_EQ(0, command_callback_count_);
+ WriteStubCommand(transport_.GetHciFd());
+ for (int i = 1; i < kMultiIterations; ++i)
+ WriteStubCommand(transport_.GetHciFd());
+ thread_.Stop(); // Wait for the command handler to finish.
+ EXPECT_EQ(kMultiIterations, command_callback_count_);
+}
+
+// TODO(dennischeng): Add tests for PostEventResponse and
+// PostDelayedEventResponse.
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 The Android Open Source Project
+//
+// 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.
+//
+
+#include "vendor_libs/test_vendor_lib/include/packet_stream.h"
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <gtest/gtest.h>
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+extern "C" {
+#include "hci/include/hci_hal.h"
+#include "stack/include/hcidefs.h"
+
+#include <sys/socket.h>
+} // extern "C"
+
+namespace {
+const char small_payload[] = "foo bar baz";
+const char large_payload[] =
+ "Aristotle's principles will then be no more principles to him, than those "
+ "of Epicurus and the Stoics: let this diversity of opinions be propounded "
+ "to, and laid before him; he will himself choose, if he be able; if not, "
+ "he will remain in doubt.";
+} // namespace
+
+namespace test_vendor_lib {
+
+class PacketStreamTest : public ::testing::Test {
+ public:
+ PacketStreamTest() {
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, socketpair_fds_);
+ CheckSocketpairInit();
+ }
+
+ ~PacketStreamTest() {
+ close(socketpair_fds_[0]);
+ close(socketpair_fds_[1]);
+ }
+
+ void CheckedReceiveCommand(const char* payload, uint16_t opcode) {
+ uint8_t payload_size = strlen(payload);
+ std::vector<uint8_t> packet;
+
+ packet.push_back(DATA_TYPE_COMMAND);
+ packet.push_back(opcode);
+ packet.push_back(opcode >> 8);
+ packet.push_back(payload_size);
+
+ // Set the packet's payload.
+ for (int i = 0; i < payload_size; ++i)
+ packet.push_back(payload[i]);
+
+ // Send the packet to |packet_stream_|.
+ write(socketpair_fds_[1], &packet[1], packet.size());
+
+ // Read the command packet.
+ std::unique_ptr<CommandPacket> command =
+ packet_stream_.ReceiveCommand(socketpair_fds_[0]);
+
+ const std::vector<uint8_t> received_payload = command->GetPayload();
+
+ // Validate the packet by checking that it's the appropriate size and then
+ // checking each byte.
+ EXPECT_EQ(packet.size(), command->GetPacketSize());
+ EXPECT_EQ(DATA_TYPE_COMMAND, command->GetType());
+ EXPECT_EQ(opcode, command->GetOpcode());
+ EXPECT_EQ(payload_size, command->GetPayloadSize());
+ for (int i = 0; i < payload_size; ++i)
+ EXPECT_EQ(packet[4 + i], received_payload[i]);
+ }
+
+ void CheckedSendEvent(std::unique_ptr<EventPacket> event) {
+ EXPECT_TRUE(packet_stream_.SendEvent(*(event.get()), socketpair_fds_[0]));
+
+ // Read the packet sent by |packet_stream_|.
+ uint8_t event_header[3];
+ read(socketpair_fds_[1], event_header, 3);
+
+ uint8_t return_parameters_size = event_header[2];
+ uint8_t return_parameters[return_parameters_size];
+ read(socketpair_fds_[1], return_parameters, sizeof(return_parameters));
+
+ const std::vector<uint8_t> expected_payload = event->GetPayload();
+
+ // Validate the packet by checking that it's the
+ // appropriate size and then checking each byte.
+ EXPECT_EQ(event->GetPacketSize(),
+ sizeof(event_header) + sizeof(return_parameters));
+ EXPECT_EQ(DATA_TYPE_EVENT, event_header[0]);
+ EXPECT_EQ(event->GetEventCode(), event_header[1]);
+ EXPECT_EQ(event->GetPayloadSize(), return_parameters_size);
+ for (int i = 0; i < return_parameters_size; ++i)
+ EXPECT_EQ(expected_payload[i], return_parameters[i]);
+ }
+
+ protected:
+ PacketStream packet_stream_;
+
+ int socketpair_fds_[2];
+
+ private:
+ // Workaround because ASSERT cannot be used directly in a constructor
+ void CheckSocketpairInit() {
+ ASSERT_TRUE(socketpair_fds_[0] > 0);
+ ASSERT_TRUE(socketpair_fds_[1] > 0);
+ }
+
+};
+
+TEST_F(PacketStreamTest, ReceivePacketType) {
+ serial_data_type_t command_type = DATA_TYPE_COMMAND;
+ write(socketpair_fds_[1], &command_type, 1);
+ EXPECT_EQ(command_type, packet_stream_.ReceivePacketType(socketpair_fds_[0]));
+}
+
+TEST_F(PacketStreamTest, ReceiveEmptyCommand) {
+ CheckedReceiveCommand("", HCI_RESET);
+}
+
+TEST_F(PacketStreamTest, ReceiveSmallCommand) {
+ CheckedReceiveCommand(small_payload, HCI_RESET);
+}
+
+TEST_F(PacketStreamTest, ReceiveLargeCommand) {
+ CheckedReceiveCommand(large_payload, HCI_RESET);
+}
+
+TEST_F(PacketStreamTest, SendEvent) {
+ const std::vector<uint8_t> return_parameters = {0};
+ CheckedSendEvent(
+ EventPacket::CreateCommandCompleteEvent(1, HCI_RESET, return_parameters));
+}
+
+} // namespace test_vendor_lib